我一直在努力完全理解移动语义,但我有一个问题,因为不同的例子显示了不同的东西。假设我们有一个类Foo,它有一个字符串成员str_。要定义移动构造函数,我应该像这样定义它:
Foo(Foo&& foo) : str_(foo.str_) { }
或者这个:
Foo(Foo&& foo) : str_(std::move(foo.str_)) { }
另外,我是否需要将我正在移动的对象的成员设置为空白值?如何在不构造另一个字符串的情况下这样做,从根本上消除了首先使用移动构造函数节省的费用?
答案 0 :(得分:0)
你应该使用第二种方法。
您不必对移动的string
执行任何操作,因为这是由string
的移动构造函数处理的。后者由move()
调用调用。
对于你自己的课程也一样,你想要move()
的任何东西都应该有一个移动构造函数。例如,如果您的类具有指针成员,则您的移动构造函数可以/应该将nullptr
分配给您move()
的对象中的该成员。
答案 1 :(得分:0)
在移动构造函数(或移动赋值运算符)中,您需要在移动单个成员时使用std::move()
(或至少在非POD成员上,因为“移动”POD类型与复制相同它)。
在Foo&& foo
中,foo
是右值引用,但foo.str_
不是。如果在移动构造函数中调用str_(foo.str_)
(或在移动赋值运算符中调用str_ = foo.str_
),它将调用字符串的复制构造函数(或复制赋值运算符)。因此,您需要通过foo.str_
将std::move()
强制转换为右值引用,以便调用字符串的移动构造函数(或移动赋值运算符)。
移动构造函数(和移动赋值运算符)负责将移动的对象保留在未指定但有效的状态,因此其析构函数不会失败。在移动foo.str_
成员的情况下,字符串的移动构造函数(或移动赋值运算符)会将foo.str_
重置为空字符串,您无需手动重置它。