【问题标题】:Placement new on this新的展示位置
【发布时间】:2012-11-22 07:51:42
【问题描述】:

我看到了一些这样的代码:

class BaseClass
{
public:
    BaseClass(int param);
};

class Derived: public BaseClass
{
};

BaseClass::BaseClass(int param)
{
    new (this) Derived;
}

代码试图做什么?我认为它会创建一个派生类对象。然而,背后的逻辑是什么?我想当我们调用 new BaseClass() 时,它只会根据基类大小分配内存。但是,为什么我们仍然可以将这个指针传递给新的位置来构造 Derived 类对象?

编辑: 谢谢回复。进一步检查,代码确实覆盖了基类的 operator new 以分配足够的内存来保存派生类对象并避免递归调用它,在派生类构造函数中,它调用了另一个基类构造函数。

基本上我认为它正在尝试创建类似于工厂的东西,其中创建对象的位置取决于参数。根据回复,这样做似乎不是一个好习惯。

【问题讨论】:

  • 呃!哇——哇!这不是好的代码。
  • 那条路是疯狂的,除非当然有might be a Curiously Recurring Template Pattern参与(你没有显示)——即使那样它也很臭
  • ...除了由于无限递归而产生 StackOverflow 之外,您的意思是?
  • @David:它甚至无法编译(Derived 没有有效的构造函数)。

标签: c++


【解决方案1】:

由于大约六亿个原因,这是一种可怕的未定义行为。永远不要这样做。

【讨论】:

  • 能否请您用 spec/doc/... 支持您的回答?
【解决方案2】:

这会在this 指向的内存上调用DerivedClass 的构造函数。所以,new 操作符不分配任何东西,它只是调用构造函数来初始化已经分配的内存中的对象。

但是,在这种特殊情况下,结果充其量是非常奇怪的。您实际上是在使用派生类的构造函数初始化基类的对象。结果是您仍然拥有基类的对象,但具有派生类的状态,或者至少假装具有这种状态。根据派生类是否引入了其构造函数引用的一些新字段,这甚至可能导致内存访问冲突......

所以,简短的建议:不要那样做。一般来说,除非您真的知道自己在做什么,否则根本不要使用 placement new

【讨论】:

    【解决方案3】:

    该代码中有很多错误。对于初学者来说,选择最简单的一个,构造函数不应该在类声明中被限定。

    接下来是它正在做的事情:看起来它正在为Base 分配的内存中创建Derived 类型的对象。

    • 这里的问题包括Derived 可能需要比Base 更多的内存,并且无法保证内存可用。
    • 它会触发一个无限递归循环,因为Base的构造函数试图创建一个Derived,然后它会尝试调用Base的构造函数,它会尝试创建一个Derived ...
    • 即使递归被切断(提供替代的Base 构造函数,并让被调用的Derived 构造函数调度到该非循环版本),并且Derived 适合Base 的内存占用,任何已经初始化的Base 的成员将被重新初始化 调用未定义的行为。例如,如果Base 包含一个在内部分配和管理内存的属性,则它的构造函数将被调用两次,从而泄漏第一次调用中获取的资源。分别构造和销毁的对象数量不匹配。
    • 可能还有很多其他问题,最多达到 DeadMG 提到的 6 个 bajillion 数字。

    【讨论】:

      【解决方案4】:

      这是未定义的行为,它可能会递归调用基类构造函数,您将获得无限递归。

      【讨论】:

        【解决方案5】:

        您的代码无法编译。

        没有为Derived 定义构造函数,编译器无法生成默认构造函数,因为Base 只有一个需要参数的构造函数。

        【讨论】:

          【解决方案6】:

          我认为这背后没有逻辑。顺便说一句,在 C++ 中,当您构建派生实例时,对象首先被初始化为基类(即首先执行基类的构造函数)。因此,我会说这段代码将永远递归地调用自身(直到堆栈空间耗尽,也就是说)。

          【讨论】:

            猜你喜欢
            • 2021-08-29
            • 2018-12-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多