C++类的构造重载、赋值重载与右值引用
为什么要重载运算符“=”和拷贝构造函数?
- 为了给类赋予新的能力的同时保持语义。比如之前文章提到的迭代器(iterator)重载自加操作符,就是为了保持语义;
- 类的职责多样,有的类的拷贝过程默认拷贝构造函数无法满足,需要定制(比如深拷贝)。
拷贝构造/移动构造函数
拷贝构造函数重载相信我们已经见过太多,无非就是这样的形式(构造函数多了个常量引用作为参数):
Foo& Foo::Foo(const Foo &f);
但是C++11带来了移动语义,我们可以定义移动构造函数,构造函数接收一个右值引用的时候,就会调用它。示例如下:
Foo& Foo::Foo(Foo &&f); // 这里通常去掉const,因为移动语义通常意味着要“偷”资源。
int main()
{
Foo f1{...}; // 省略掉了初始化
Foo f2(f1); // 这里调用拷贝构造函数
Foo f3(std::move(f1)); // 这里将调用移动构造函数,因为std::move返回了f1的右值引用,f1成为将亡值
// 将亡值f1被释放或被重新分配资源
// ...
// ...
return 0;
}
赋值/移动赋值函数
思路基本和拷贝构造/移动构造函数之间的关系差不多,下面是函数声明:
Foo& operator=(const Foo& f); // 这里返回reference to this,性能比返回拷贝要好些
Foo& operator=(Foo &&f); // 里面要进行“偷”资源的操作,并且一定要传入右值引用才能启用