2015-08-03 33 views
3

由于C++ 11在使用移动赋值操作符时,是否应该将我所有的数据(包括POD类型)都包含在内?我想这对下面的例子没有什么影响,但我想知道普遍接受的最佳做法是什么。C++移动赋值运算符:我想用POD类型使用std :: swap吗?

示例代码:

class a 
{ 

    double* m_d; 
    unsigned int n; 

public: 

    /// Another question: Should this be a const reference return? 
    const a& operator=(a&& other) 
    { 
     std::swap(m_d, other.m_d); /// correct 
     std::swap(n, other.n); /// correct ? 
     /// or 
     // n = other.n; 
     // other.n = 0; 
    } 
} 

你可能想考虑形式的构造: - 即:有在nm_d总是“有意义”或定义的值存储。

a() : m_d(nullptr), n(0) 
{ 
} 
+0

为了您的评论的问题,它应该是一个'&运算符=(A &&等)' – Jarod42

+0

你或许可以只使用'N = other.n',随着移动,从对象应处于有效状态留(该标准没有指定结束状态)。 – vsoftco

+1

@vsoftco如果n是动态数组的大小,那么它应该设置为0或'other.n',具体取决于使用'm_d'完成的操作。 – juanchopanza

回答

1

我应该化std :: swap我所有的数据

一般不。移动语义可以让事情变得更快,并且交换直接存储在对象中的数据通常比复制数据要慢,并且可能会为某些移出的数据成员分配一些值。

对于您的具体方案......

class a 
{ 
    double* m_d; 
    unsigned int n; 

...这是不够的,只考虑数据成员知道什么是有意义的。举例来说,如果你用你的假设交换非POD成员和分配,否则的组合...

 std::swap(m_d, other.m_d); 
    n = other.n; 
    other.n = 0; 

...在移动构造函数或赋值操作符,那么它仍然可能离开,如果你的程序的状态无效说析构函数跳过删除m_dn0,或者如果它在覆盖m_d之前选中n == 0并指向新分配的内存,旧的内存可能会泄漏。您必须决定类不变量:m_dn的有效关系,以确保您的移动构造函数和/或赋值运算符保留对未来操作有效的状态。 (大多数情况下,移动对象的析构函数可能是唯一需要运行的东西,但它对于程序重用移动后的对象是有效的 - 例如为其赋值一个新值并在循环的下一次迭代中处理它....)

另外,如果你不变量允许非nullptrm_dn == 0,然后交换m_d s的吸引力,因为它给人的感动,从物体持续控制任何缓冲移动到对象可能有:可节省稍后再分配缓冲区;反平衡的亲,如果缓冲区不需要以后,你已经把它分配的时间超过必要的,如果它不够大,你会最终删除和新的更大的缓冲区,但至少你是懒惰的这往往有助于提高绩效(但如果你必须关心的话,就是个人资料)。

1

不,如果效率有任何问题,请不要交换POD。与正常分配相比,它没有任何好处,只会导致不必要的副本。还要考虑是否将从POD移动到0的设置甚至是必需的。

我甚至不会交换指针。如果这是一种拥有关系,请使用unique_ptr并从中移出,否则就像POD一样对其进行处理(将其复制并设置为nullptr或之后的任何程序逻辑要求)。

如果您不必将POD设置为零并且使用智能指针,则根本不需要实现移动操作符。

关于你问题的第二部分: 正如Mateusz已经指出的那样,赋值运算符应该总是返回一个正常的(非const)引用。

2

我认为这应该以这种方式重写。

class a 
{ 
public: 
    a& operator=(a&& other) 
    { 
     delete this->m_d; // avoid leaking 
     this->m_d = other.m_d; 
     other.m_d = nullptr; 
     this->n = other.n; 
     other.n = 0; // n may represents array size 
     return *this; 
    } 
private: 
    double* m_d; 
    unsigned int n; 
}; 
+1

对于你的'operator =',你可能想在泄漏它之前先删除m_d;有些关于'other.n'可能发生的旧的讨论会帮助读者理解为什么你会认为这应该被重写。 –

+1

从[standard](http://stackoverflow.com/a/12095473/5037799):'除非另有规定,否则这些从对象移出的对象应置于有效但未指定的状态.'对于unsigned int,没有有效值设置一个未指定的状态。 –

+2

你误解了这个需求 - *对象*需要处于有效状态,而不是孤立的'unsigned int'成员。这意味着,无论其他操作尝试移动从“a”的实例必须工作每类API:例如,如果有一个现有的索引'运算符[](INT我)'执行'assert(我