11

背景: 我有一个复杂的类,有很多变量。我有一个健全且经过测试的复制构造函数:

Applepie::Applepie( const Applepie &copy) :
m_crust(copy.m_crust),
m_filling(copy.m_filling)
{
}

初始化器列表中调用的一些成员变量复制构造函数执行分配。

问题: 我需要创建operator=. 我可以简单地执行以下操作,而不是使用赋值而不是初始化列表来复制现有的构造函数,并释放正在被替换的内存等等等等:

Applepie& Applepie::operator=( const Applepie &copy)
{
    if( this != &copy)
    {
       this->~Applepie(); // release own object
       new(this) Applepie(copy); // placement new copy constructor
    }
    return *this;
}

换句话说,destroy self 后跟一个placement new 复制构造函数在语义上与 operator= 相同吗?

这似乎有可能显着减少重复代码并确认每个变量都已正确初始化,但代价是分配期间可能会轻微降低效率。我错过了一些更模糊的东西吗?

理由: 我的实际班级有大约 30 个变量。我担心我的复制构造函数和赋值运算符都必须复制所有 30 个,并且代码可能会出现分歧,导致这两个操作做不同的事情。

4

2 回答 2

6

正如“Exceptional C++”中的 Herb Sutter 所说,它不是异常安全的。这意味着,如果new在新对象的构建或构造过程中出现任何问题,则赋值的左侧操作数处于错误(未定义)状态,需要更多麻烦。我强烈建议使用copy & swap idiom

Applepie& Applepie::operator=(Applepie copy)
{
  swap(m_crust, copy.m_crust);
  swap(m_filling, copy.m_filling);
  return *this;
}

当您的对象也使用Pimpl 习惯用法(指向实现的指针)时,只需更改两个指针即可完成交换。

于 2011-08-24T15:23:20.710 回答
1

除了 Rene 的回答之外,还有一个问题是如果 ApplePie 是实际对象的基类会发生什么:ApplePie 会用错误类型的对象替换该对象!

于 2011-08-24T15:31:39.223 回答