从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;
}
}
您可能想考虑以下形式的构造函数:-即:在
n
或m_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_d
为n
时析构函数跳过删除0
,或者在用指向新分配的内存,旧内存的指针覆盖n == 0
之前检查了m_d
,则它可能仍使程序状态无效。可能会泄漏。您必须确定类不变式:m_d
和n
的有效关系,以确保您的move构造函数和/或赋值运算符使状态对于以后的操作有效。 (通常,移出对象的析构函数可能是剩下的唯一要运行的东西,但是对于程序重用移出对象是有效的,例如,为其分配新值并在下一次循环迭代中对其进行处理....)另外,如果您的不变量在
nullptr
时允许一个非m_d
n == 0
,那么交换m_d
会很吸引人,因为它可以使移出对象继续控制移入对象可能拥有的任何缓冲区:这样可以节省以后分配缓冲区的时间;平衡该专业人士,如果以后不需要缓冲区时,您将其分配的时间超过了必要的时间,如果缓冲区不够大,您最终将删除并新建一个较大的缓冲区,但至少您对此很懒这往往有助于提高性能(但如果需要的话,请关注个人资料)。