可能这个问题已经被问过了,但我不知道该搜索什么。
如果数据成员定义了move赋值操作符,可以将move语义用于非指针数据成员吗?
假设我有一个类M
,它这样定义M::operator=(M&&)
:
template <class T>
class M
{
public:
M()
{
mem_M = new T;
}
M& operator=(M&& src)
{
if (this != &src)
{
mem_M = src.mem_M;
src.mem_M = nullptr;
}
return *this;
}
private:
T* mem_M;
};
现在显然我可以有一个类C<T>
这样,移动构造函数不使用T
的移动赋值操作符:
template <class T>
class C
{
public:
C ()
{
mem_C = new T;
}
C (C&& rhs)
{
mem_C = rhs.mem_C;
rhs.mem_C = nullptr;
}
private:
T* mem_C;
};
然而,如果我想让C<T>::mem_C
不是指针而是普通成员,我该如何处理移动函数中的C<T>::mem_C
呢?我当然可以调用移动赋值运算符T::operator=(T&&)
来将文件mem_C
从一个实例移动到另一个实例,但是我如何正确地重置传递给C<T>::C(C&&)
的C
的实例呢?
这至少在我看来是错误的:
template <class T>
class C
{
public:
C ()
{
mem_C = T();
}
C (C<T>&& rhs)
{
mem_C = std::move(rhs.mem_C);
rhs.mem_C = T(); // ?? like this?
}
private:
T mem_C;
};
那么,在移动函数中重置非指针数据成员的标准兼容方式是什么?
所包含类型的move赋值/构造函数必须使对象处于"可接受"状态,无论这对该类型意味着什么。被移动的类型之外的任何东西都不应该负责维护对象的状态。
另外,你要确保你调用的是父类move 构造函数中包含类型的move 构造函数,而不是包含类型的move 赋值,就像你在上面的例子中:
// move constructor calls move constructor of contained elements
C (C<T>&& rhs) : mem_c(std::move(rhs.mem_c))
{
// anything in here is using already-constructed data members
}
// move assignment calls move assignment of contained elements
C & operator=(C<T>&& rhs) {
mem_c = std::move(rhs.mem_c);
}