移动语义及拷贝优化
原地址:https://cloud.tencent.com/developer/article/1385969
左值和右值
C++中如何区分一个变量是左值还是右值呢?
- 左值一般是可寻址的变量,右值一般是不可寻址的字面常量或者是在表达式求值过程中创建的可寻址的无名临时对象;
- 左值具有持久性,右值具有短暂性。
左值引用的符号为"&"(传统C++中的引用);右值引用的符号为"&&"(C++ 11中的新特性)
移动构造函数和移动赋值函数
移动语义和拷贝语义是相对的,移动类似于计算机中对文件操作的剪切,而拷贝类似于文件的复制。
我们可以定义拷贝构造函数和赋值函数进行对象的复制,如果没有定义,编译器会帮我们生产默认的实现。要实现转移语义,需要定义转移构造函数,当然还可以定义转移赋值操作符。对于右值的拷贝和赋值会调用转移构造函数和转移赋值操作符。如果转移构造函数和转移拷贝操作符没有定义,那么拷贝构造函数和赋值操作符会被调用。
移动构造函数和移动赋值函数都是形参(Parameter)为右值引用的函数,下面看一个例子:
1 struct Foo {
2 Foo() { cout << "Constructed" << endl; }
3 Foo(const Foo &) { cout << "Copy-constructed" << endl; }
4
5 ~Foo() { cout << "Destructed" << endl; }
6 };
7 int main() {
8 vector<Foo> vec;
9 vec.push_back(Foo());
10
11 return 0;
12 }
可以看到拷贝构造函数被调用了。在主函数中的第3上,Foo()
会生成一个右值对象(调用默认构造函数),然后进行拷贝构造以后传递给vec
集合。
1 struct Foo {
2 Foo() { cout << "Constructed" << endl; }
3 Foo(const Foo &) { cout << "Copy-constructed" << endl; }
4 Foo(Foo &&) { cout << "Move-constructed" << endl; }
5 ~Foo() { cout << "Destructed" << endl; }
6 };
7 int main() {
8 vector<Foo> vec;
9 vec.push_back(Foo());
10 return 0;
11 }
这时,因为Foo()
是右值,所以调用了移动构造函数。
NOTE:拷贝构造函数中是对传进来的对象进行了实实在在的拷贝工作;而移动构造函数中只是对传进来的对象进行了所有权的转让,即掏空传进来的对象,然后把所有权转给当前对象(this
指针指向的那个对象)。