C++移动语义
愤怒的小黄鸭 人气:0引入移动语义
为了能够理解移动语义的目的,我们先从整成的一个类进行示范,示例如下:
class TestClass { public: TestClass(int s) :m_number(s) { cout << "constructor!\n"; } ~TestClass() { cout << "destructor!\n"; } // 拷贝构造 TestClass(const TestClass& that) :m_number(that.m_number) { cout << "copy constructor!\n"; } // 赋值操作符 TestClass& operator=(const TestClass& tc) { cout << "operator= is called\n"; if (this == &tc) return *this; m_number = 0; m_number = tc.m_number; return *this; } int m_number; }; TestClass tcFactory() { TestClass tc(10); return tc; } int main() { { TestClass tc = tcFactory(); } return 0; }
上面代码的输出结果如下:
constructor!
copy constructor!
destructor!
destructor!
可以看到进行了一次构造和一次拷贝构造,拷贝构造就发生在tc
接收tcFactory()
返回值时。这几产生了不必要的资源消耗,如果这里可以重用或者转移return
产生的临时值(右值)是不是可以减少资源的消耗呢?C++正是使用转移的方式来处理的,这个转移就是移动构造函数,也可以说是移动语义,示例如下:
// 其他代码不变,只增加移动构造与移动赋值处理函数 // 移动构造 TestClass(TestClass&& rr):m_number(rr.m_number) { // 如果这里是指针的变量的话则可以避免指针重复释放的问题 rr.m_number = 0; cout << "move constructor!\n"; } // 移动赋值 TestClass& operator=(TestClass&& rr) { cout << "move operator= is called\n"; if (this == &rr) return *this; // 此步骤相当于对源指针的释放 m_number = 0; m_number = rr.m_number; return *this; }
添加上述代码后,输出结果如下:
constructor!
move constructor!
destructor!
destructor!
此时第二次调用的就是移动构造,这样可以直接使用右值,避免重新申请空间,调用两次析构是因为,临时对象是被延长了声明周期,但最终也是要释放的。
std::move
前面看到移动构造接收的是右值引用,那么在需要对左值进行移动语义的时候(进行移动语义后,此左值以后将失效),那么就必须将左值转换为右值。此时td::move
就很好的完成了这件事情,示例如下:
int main() { vector<int> v{ 1,2,3,4 }; // 拷贝构造 vector<int> v1 = v; // 移动构造 vector<int> v2 = std::move(v); cout << "v size():" << v.size() << "\n"; cout << "v2 size():" << v2.size() << "\n"; return 0; }
上面输出代码为:
v size():0
v2 size():4
关于std::move
注意的几点:
std::move
本质上只是将传入的参数转换为一个右值,使用static_cast
进行转换
std::move
在进行类型推导时会保留形参的const
属性,此时会造成一种使用失效的场景如下:
class TestClass { public: // 这么写在 VS中也会提示 C26478 不要对常量变量使用 std::move TestClass(const string& str) :m_str(std::move(str)) { } string m_str; }; int main() { string str = "sss"; TestClass tc(str); cout << tc.m_str << "\n"; // 此处应该输出空,但实际并非如此 , 两个输出都是 sss cout << str << "\n"; return 0; }
加载全部内容