C++ 我可以在运算符=(中)中使用placement new(this)吗?

C++ 我可以在运算符=(中)中使用placement new(this)吗?,c++,operator-overloading,placement-new,C++,Operator Overloading,Placement New,背景: 我有一个有很多变量的复杂类。我有一个可靠且经过测试的复制构造函数: Applepie::Applepie( const Applepie &copy) : m_crust(copy.m_crust), m_filling(copy.m_filling) { } 初始化器列表中调用的一些成员变量复制构造函数执行分配 问题: 我需要创建操作符=。与其使用赋值而不是初始化列表复制现有构造函数,并释放正在被替换的内存,等等,我可以简单地执行以下操作: Applepie& App

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

Applepie::Applepie( const Applepie &copy) :
m_crust(copy.m_crust),
m_filling(copy.m_filling)
{
}
初始化器列表中调用的一些成员变量复制构造函数执行分配

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

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 copy构造函数在语义上是否与operator=相同

这似乎有可能大大减少重复代码,并确认每个变量都已正确初始化,但在赋值过程中可能会略微降低效率。我是不是错过了一些更模糊的东西

理由: 我的实际班级大约有30个变量。我担心的是,我的复制构造函数和赋值运算符都必须复制全部三十个,而且代码可能会发散,导致这两个操作的操作方式不同。

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

当您的对象也使用Pimpl惯用语(指向实现的指针)时,交换仅通过更改两个指针来完成。

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



当您的对象也使用Pimpl惯用语(指向实现的指针)时,交换仅通过更改两个指针来完成。

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

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

如果复制ctor抛出,则表示您已破坏了对象,因此您没有提供任何预期的安全保证。@R Martinho--在我看来,复制ctor抛出的任何情况都会导致我的运算符=抛出,如果我手动分配每个变量。。。所以这似乎仍然是等价的?问题不是
operator=
抛出,而是
operator=
使对象处于无效状态!苹果派真的需要30个成员变量吗?任何类都需要30个成员变量吗?可疑的这些成员中的一些可以合并成合理的类吗?mably.jcwenger:copy and swap idium使用copy cnstructor,但如果复制构造函数抛出,则不会使当前对象保持无效状态。在您的版本中,无论发生什么,您都会丢失对象,因此异常将导致系统中存在无效对象(这是不可取的)。不应存在任何不提供任何保证的零代码。如果复制构造函数抛出,则表示您已破坏了对象,因此您没有提供任何预期的安全保证。@R Martinho--在我看来,复制构造函数抛出的任何情况都会导致我的运算符=抛出,如果我手动分配每个变量。。。所以这似乎仍然是等价的?问题不是
operator=
抛出,而是
operator=
使对象处于无效状态!苹果派真的需要30个成员变量吗?任何类都需要30个成员变量吗?可疑的这些成员中的一些可以合并成合理的类吗?mably.jcwenger:copy and swap idium使用copy cnstructor,但如果复制构造函数抛出,则不会使当前对象保持无效状态。在您的版本中,无论发生什么,您都会丢失对象,因此异常将导致系统中存在无效对象(这是不可取的)。不应该有零代码提供任何保证。+1
swap
是一个奇妙的低估功能。。。附加优点:如果参数是右值,编译器可以执行复制省略。。。我的问题是,我的实际类有大约30个变量。我的复制构造函数在初始值设定项列表中包含所有30个变量。复制和交换仍然需要我有30个swap()调用——我的目标是减少Applepie(原始)的可能性;苹果和苹果;苹果=原创;产生不同的结果。@JC温格:是的,这是自找麻烦。所以它可能是piml习惯用法的一个候选,但是在切换到它之前,要考虑它是有代价的:每个成员访问都是通过指针进行的。另一个想法是将您的
Applepie
类拆分为更小的部分。如果一个类中有30个数据成员,那么设计可能有问题…@jcnenger:我想说,你的真正目标是编写难以破解的代码。复制和交换习惯用法就是这样做的。我认为你是在试图弥补其他问题(比如30名成员)。为了提高效率,您的对象应该已经有了swap()方法。这样,赋值运算符就变成了对复制构造函数的调用,然后是对swap()的调用。如果没有看到代码,这是很困难的,但是如果您的类正在管理资源(否则编译器生成的复制构造函数和赋值将起作用),并且您有30多个字段。。。这有点像密码的味道。考虑修改设计来划分职责。+ 1代码>交换<代码>是一个很好的被低估的函数…附加优点:编译器可以执行
Applepie& Applepie::operator=(Applepie copy)
{
  swap(m_crust, copy.m_crust);
  swap(m_filling, copy.m_filling);
  return *this;
}