自我毁灭:this-> MyClass ::〜MyClass()与this->〜MyClass() [英] Self destruction: this->MyClass::~MyClass() vs. this->~MyClass()

查看:93
本文介绍了自我毁灭:this-> MyClass ::〜MyClass()与this->〜MyClass()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在学习C ++的过程中,我偶然发现了文章编写副本构造函数和赋值运算符,其中提出了一种避免这种情况的机制复制副本构造函数和赋值运算符之间的代码。



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

 结构UtilityClass 
{
...

UtilityClass(UtilityClass const& rhs)
:data_( new int(* rhs_.data_))
{
//这里无事可做
}

UtilityClass& operator =(UtilityClass const& rhs)
{
//
//将所有工作留给副本构造函数。
//

if(this!=& rhs)
{
//解构自己
this-> UtilityClass ::〜UtilityClass( );

//通过从右侧进行复制来重建自己。
new(this)UtilityClass(rhs);
}

return * this;
}

...
};

这似乎是避免代码重复并确保程序完整性的好方法,但需要权衡有浪费精力释放然后分配嵌套的内存的风险,而嵌套的内存却可以重复使用(正如作者指出的那样。)。



但是我不熟悉核心语法:

  this-> UtilityClass ::〜UtilityClass()


有人可以向我解释此语法,或指向我



该调用与以下内容有何不同?

  this->〜UtilityClass()

这是合法电话吗?

解决方案

TL; DR不要这样做吗?



要回答特定的问题:



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



一个合格的调用:

  this-> UtilityClass ::〜UtilityClass()

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



一个不合格的调用:

  this->〜UtilityClass()

将使用虚拟调度来



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



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



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



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


In my quest to learn C++ I stumbled across the article Writing Copy Constructors and Assignment Operators which proposes a mechanism to avoid code duplication across copy constructors and assignment operators.

To summarise/duplicate the content of that link, the proposed mechanism is:

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 seems like a nice way to avoid code duplication whilst ensuring "programatic integrity" but needs weighed against the risk of wasting effort freeing-then-allocating nested memory that could, instead, be re-used (as its author points out).

But I'm not familiar with the syntax that lies at its core:

this->UtilityClass::~UtilityClass()

I assume that this is a way to call the object's destructor (to destroy the contents of the object structure) whilst keeping the structure itself. To a C++ newbie, the syntax looks like a strange mixture of an object method and a class method.

Could someone please explain this syntax to me, or point me to a resource which explains it?

How does that call differ from the following?

this->~UtilityClass()

Is this a legitimate call? Does this additionally destroy the object structure (free from heap; pop off the stack)?

解决方案

TL;DR DO NOT DO THIS.

To answer the specific question:

In this particular example, there's no difference. As explained in the article you link to, there would be a difference if this were a polymorphic base class, with a virtual destructor.

A qualified call:

this->UtilityClass::~UtilityClass()

would specifically call the destructor of this class, not that of the most derived class. So it only destroys the subobject being assigned to, not the entire object.

An unqualified call:

this->~UtilityClass()

would use virtual dispatch to call the most derived destructor, destroying the complete object.

The article writer claims that the first is what you want, so that you only assign to the base sub-object, leaving the derived parts intact. However, what you actually do overwrite part of the object with a new object of the base type; you've changed the dynamic type, and leaked whatever was in the derived parts of the old object. This is a bad thing to do in any circumstances. You've also introduced an exception issue: if the construction of the new object fails, then the old object is left in an invalid state, and can't even be safely destroyed.

UPDATE: you also have undefined behaviour since, as described in another answer, it's forbidden to use placement-new to create an object on top of (part of) a differently-typed object.

For non-polymorphic types, a good way to write a copy-assignment operator is with the copy-and-swap idiom. That both avoids duplication by reusing the copy-constructor, and provides a strong exception guarantee - if the assignment fails, then the original object is unmodified.

For polymorphic types, copying objects is more involved, and can't generally be done with a simple assignment operator. A common approach is a virtual clone function, which each type overrides to dynamically allocate a copy of itself with the correct type.

这篇关于自我毁灭:this-> MyClass ::〜MyClass()与this->〜MyClass()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆