为类分配的实现

时间:2015-01-31 14:15:57

标签: c++

所以我在C ++中阅读了一段文本并遇到了以下代码:

class example
{
    int dataMember;

public:
    example& assign(const example& source)
    {
        if(this!=&source)
        {
            this->~example();
            new (this) example(source);
        }


    }

};

好的,所以我试图解码这个函数分配正在做什么。我的理解还是:

  1. 该函数对类的实例进行常量引用,并返回对该类的引用。

  2. if块内,首先为当前实例调用析构函数(据我所知,当前对象被销毁并释放内存)。

  3. 现在主要问题是:

    new (this) example(source)

    这条线让我很烦恼。这里发生了什么? 如果我被要求猜测,我会说正在创建一个新对象并将其指定为当前对象,我可以从this关键字推断出来。

    任何人都可以解决这个问题吗?究竟是怎么回事?

    这种方法安全吗? (如果分配是动态发生的,程序员将来必须手动解除分配)

    感谢。

2 个答案:

答案 0 :(得分:3)

您所看到的是尝试代码重用。我们的想法是使用复制构造函数来实现赋值运算符(或者,在本例中为赋值函数)。

首先,摆脱简单的东西:

  • if可确保正确处理自我分配(例如x.assign(x))。这是必要的,因为实施依赖于更改*this不会更改source这一事实。通过将this与另一个对象的地址进行比较,这会测试对象是否相等,但是为了相同性。

  • 该函数缺少return *this;,但您可能已经注意到了这一点。

现在剩下的两行:

this->~example();

显式调用类example的析构函数。在该行之后,this指针不再指向一个对象,而是指向未sizeof(example)的未初始化内存。

new (this) example(source);

是所谓的placement new分配内存,只是在example指向的位置通过调用创建新的this它的复制构造函数。在某种程度上,这是显式调用构造函数的语法,无需分配任何内存。

请注意,这会重复使用先前*this所拥有的内存,无论它在哪里:它甚至可以是例如动态分配数组元素的virtual基础...

关于安全性:在实践中,只要构造函数和析构函数都没有抛出,这就是安全的(尽管很难看并且可能效率不高)。但是,当你从一个试图偷偷摸摸的类派生时,你可能会遇到问题。

如果您想知道编写重用复制构造函数的赋值运算符/函数的最简单方法,请选中this question,其基本归结为:

example& assign(example source)
{
    swap(*this, source);
    return *this;
}

最重要的差异:

  • 它适用于移动构造函数。
  • 如果复制/移动构造函数和swap异常安全(它们应该始终存在),则此代码是异常安全的。
  • 自我分配效率略低,因为它会执行副本,而不是识别自我分配。

答案 1 :(得分:1)

这部分破坏了对象:

this->~example();

除了由于析构函数调用而释放的内存之外,它不会释放内存。然后,它继续调用" placement new":

new (this) example(source);

这将在前一个对象的(未发布的)内存上构造一个对象。

关于此的安全性,至少是危险的。如果在销毁对象后无法创建新对象,则会有一个奇怪的僵尸对象,当其正常生命周期结束时会再次被破坏(导致未定义的行为)。