从C++ 11开始,使用移动分配运算符时,我应该对所有数据(包括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)
{
}

最佳答案



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

对于您的特定情况...

class a
{
     double* m_d;
     unsigned int n;

...仅仅考虑数据成员以了解什么才是有意义的。例如,如果您对非POD成员使用分配的交换假设,否则对分配进行分配...
     std::swap(m_d, other.m_d);
     n = other.n;
     other.n = 0;

...在move构造函数或赋值运算符中,如果说在m_dn时析构函数跳过删除0,或者在用指向新分配的内存,旧内存的指针覆盖n == 0之前检查了m_d,则它可能仍使程序状态无效。可能会泄漏。您必须确定类不变式:m_dn的有效关系,以确保您的move构造函数和/或赋值运算符使状态对于以后的操作有效。 (通常,移出对象的析构函数可能是剩下的唯一要运行的东西,但是对于程序重用移出对象是有效的,例如,为其分配新值并在下一次循环迭代中对其进行处理....)

另外,如果您的不变量在nullptr时允许一个非m_d n == 0,那么交换m_d会很吸引人,因为它可以使移出对象继续控制移入对象可能拥有的任何缓冲区:这样可以节省以后分配缓冲区的时间;平衡该专业人士,如果以后不需要缓冲区时,您将其分配的时间超过了必要的时间,如果缓冲区不够大,您最终将删除并新建一个较大的缓冲区,但至少您对此很懒这往往有助于提高性能(但如果需要的话,请关注个人资料)。

10-08 08:28
查看更多