C++ 具有非指针数据成员的移动语义

C++ 具有非指针数据成员的移动语义,c++,pointers,move-semantics,C++,Pointers,Move Semantics,也许这个问题已经被问到和回答了,但我不知道该搜索什么 如果数据成员定义了移动赋值运算符,则可以将移动语义用于非指针数据成员吗 假设我有一个类M,它定义了M::operator=(M&&),如下所示: template <class T> class M { public: M() { mem_M = new T; } M& operator=(M&& src) { if (this !

也许这个问题已经被问到和回答了,但我不知道该搜索什么

如果数据成员定义了移动赋值运算符,则可以将移动语义用于非指针数据成员吗

假设我有一个类
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::mem_C
不是指针而是普通成员,我将如何处理move函数中的
C::mem_C
?当然,我可以调用move assignment操作符
T::operator=(T&&&)
将字段
mem_C
从一个实例移动到另一个实例,但是如何正确重置传递给
C::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;
};
模板
C类
{
公众:
C()
{
mem_C=T();
}
C(C&rhs)
{
mem_C=std::move(rhs.mem_C);
像这样的rhs.mem_C=T();/?
}
私人:
T mem_C;
};

那么,在移动函数中重置非指针数据成员的标准兼容方式是什么呢?

所包含类型的移动赋值/构造函数必须使对象保持“可接受”状态,无论这对该类型意味着什么。要移动的类型之外的任何内容都不应负责维护对象的状态

另外,您要确保调用的是父移动构造函数中包含类型的移动构造函数,而不是示例中包含类型的移动赋值:

// 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);
}
//move构造函数调用包含元素的move构造函数
C(C&&rhs):mem_C(标准::move(rhs.mem_C))
{
//这里的任何内容都使用已构造的数据成员
}
//移动分配调用包含元素的移动分配
C&operator=(C&rhs){
mem_c=std::move(rhs.mem_c);
}

所包含类型的移动赋值/构造函数必须使对象保持“可接受”状态,无论这对该类型意味着什么。要移动的类型之外的任何内容都不应负责维护对象的状态

另外,您要确保调用的是父移动构造函数中包含类型的移动构造函数,而不是示例中包含类型的移动赋值:

// 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);
}
//move构造函数调用包含元素的move构造函数
C(C&&rhs):mem_C(标准::move(rhs.mem_C))
{
//这里的任何内容都使用已构造的数据成员
}
//移动分配调用包含元素的移动分配
C&operator=(C&rhs){
mem_c=std::move(rhs.mem_c);
}

指针是“普通成员”的子集。您似乎在询问移动类类型和非类类型之间的区别
mem_C=T()应该被删除,对象已经被构造,因此这只会浪费时间和资源。在这种情况下,您可以也应该使用默认的移动分配运算符(请参见)@M.M,但是如果
mem_C
是一百万个元素的向量?释放空间不值得花时间重新初始化
mem\u C
?例如,如果
T
vector
,那么当构造函数运行时,它是一个空向量;将其设置为空向量不会释放任何内容,只会浪费时间。指针是“普通成员”的子集。您似乎在询问移动类类型和非类类型之间的区别
mem_C=T()应该被删除,对象已经被构造,因此这只会浪费时间和资源。在这种情况下,您可以也应该使用默认的移动分配运算符(请参见)@M.M,但是如果
mem_C
是一百万个元素的向量?释放空间不值得花时间重新初始化
mem\u C
?例如,如果
T
vector
,那么当构造函数运行时,它是一个空向量;将其设置为空向量不会释放任何内容,只会浪费时间。