【发布时间】:2020-09-06 21:04:06
【问题描述】:
隐式移动构造函数执行成员方式移动和隐式移动赋值运算符执行成员方式分配是什么意思?
来自https://en.cppreference.com/w/cpp/language/move_constructor:
对于非联合类类型(类和结构),move 构造函数 对对象的基础和非静态执行完整的成员移动 成员,按其初始化顺序,使用直接初始化 带有 xvalue 参数。如果这满足一个要求 constexpr构造函数,生成的move构造函数是constexpr。
来自https://en.cppreference.com/w/cpp/language/move_assignment:
对于非联合类类型(class 和 struct),move 赋值 运算符执行对象的完整成员移动分配 直接基数和直接非静态成员,在其声明中 顺序,对标量使用内置赋值,按成员 数组的移动赋值,类的移动赋值运算符 类型(非虚拟调用)。
以下示例类模板的隐式成员是否如下所示:
template<class T>
class Holder {
public:
Holder(int size) : m_size(size) { m_data = new T[m_size]; }
Holder(Holder && other) :
m_size(std::move(other.m_size)),
m_data(std::move(other.m_data))
{}
Holder& operator=(Holder && other) {
if(this == &other) return *this;
m_data = std::move(other.m_data);
m_size = std::move(other.m_size);
return *this;
}
~Holder() { delete [] m_data; }
private:
T* m_data;
int m_size;
};
还有,上例中的std::move()会转移什么资源?
【问题讨论】:
-
如果您要实现一个移动构造函数,该构造函数单独移动每个基数以及每个成员 - 并在初始化列表中执行此操作 - 您将完全实现“完整成员明智的举动”。同样,如果您实现移动赋值运算符来移动所有基和所有成员。
-
移动原始指针(如您的
m_data)只会导致指针的副本,这通常会破坏程序。m_data(std::exchange(other.m_data, nullptr))在您的情况下可能是正确的做法。 -
是的,但我的意思是隐式析构函数和复制运算符会做什么?
-
当
Holder被销毁时,T*和int占用的空间将被释放。如果没有显式析构函数,m_data指向的任何数据都将被泄露。它会不会delete[]它为您服务。隐式复制运算符只会复制值。它不会复制m_data指向的内容。如果你使用它,你将有两个指向相同数据的对象,并且它会被释放两次(UB)。
标签: c++ c++11 language-lawyer move-semantics