在学习C++的过程中,我偶然发现了Writing Copy Constructors and Assignment Operators文章,该文章提出了一种避免在复制构造函数和赋值运算符之间进行代码重复的机制。

为了总结/复制该链接的内容,建议的机制是:

struct UtilityClass
{
  ...

  UtilityClass(UtilityClass const &rhs)
    : data_(new int(*rhs_.data_))
  {
    // nothing left to do here
  }

  UtilityClass &operator=(UtilityClass const &rhs)
  {
    //
    // Leaves all the work to the copy constructor.
    //

    if(this != &rhs)
    {
      // deconstruct myself
      this->UtilityClass::~UtilityClass();

      // reconstruct myself by copying from the right hand side.
      new(this) UtilityClass(rhs);
    }

    return *this;
  }

  ...
};

这似乎是避免代码重复并确保“程序完整性”的一种好方法,但需要权衡浪费精力的浪费,然后分配嵌套的内存,这些内存可以重新使用(如其作者所指出)。

但是我不熟悉其核心的语法:
this->UtilityClass::~UtilityClass()

我假设这是一种在保留结构本身的同时调用对象的析构函数(破坏对象结构的内容)的方法。对于C++新手来说,语法看起来像是对象方法和类方法的奇怪混合体。

有人可以向我解释此语法,还是可以向我指出解释该语法的资源?

该电话与以下电话有何不同?
this->~UtilityClass()

这是合法电话吗?这是否还会破坏对象结构(没有堆;从堆栈弹出)?

最佳答案

TL; DR请勿这样做。

要回答特定问题:

在此特定示例中,没有区别。如您所链接的文章中所述,如果这是带有虚拟析构函数的多态基类,则会有区别。

合格的电话:

this->UtilityClass::~UtilityClass()

将专门调用此类的析构函数,而不是大多数派生类的析构函数。因此,它只会破坏分配给它的子对象,而不破坏整个对象。

不合格的电话:
this->~UtilityClass()

将使用虚拟分派(dispatch)调用最派生的析构函数,从而破坏整个对象。

本文作者声称,第一个是您想要的,因此您只分配给基本子对象,而派生部分保持完整。但是,您实际执行的操作是使用基本类型的新对象覆盖对象的一部分。您已经更改了动态类型,并且泄漏了旧对象派生部分中的所有内容。在任何情况下,这都是一件坏事。您还引入了一个异常(exception)问题:如果新对象的构建失败,那么旧对象将处于无效状态,甚至无法安全销毁。

更新:您还具有未定义的行为,因为如另一个答案所述,禁止使用newplacement在不同类型的对象(的一部分)之上创建对象。

对于非多态类型,编写副本分配运算符的一种好方法是使用copy-and-swap idiom。两者都通过重用copy-constructor来避免重复,并提供了强大的异常保证-如果分配失败,则原始对象不会被修改。

对于多态类型,复制对象更为复杂,通常无法通过简单的赋值运算符完成。一种常见的方法是虚拟clone函数,每种类型都可以覆盖该函数以动态分配具有正确类型的自身副本。

关于c++ - 自我破坏:this-> MyClass::〜MyClass()与this->〜MyClass(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25365088/

10-10 05:07