在此放置新的

时间:2011-04-29 12:08:18

标签: c++

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

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

class Derived: public BaseClass
{
};

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

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

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

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

7 个答案:

答案 0 :(得分:13)

这是大约六个bajillion原因的可怕的未定义行为。不要永远这样做。

答案 1 :(得分:6)

这会在DerivedClass指向的内存上调用this的构造函数。因此,new运算符不会分配任何内容,它只是调用构造函数来初始化已经分配的内存中的对象。

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

所以,简短的建议:不要这样做。一般情况下,除非你真的知道自己在做什么,否则不要使用 placement new

答案 2 :(得分:2)

该代码中存在许多错误。对于初学者来说,要选择一些简单的构造函数,构造函数不应该在类声明中进行限定。

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

  • 这里的问题包括Derived可能需要比Base更多的内存,并且无法保证内存可用。
  • 它将触发一个无限递归循环,因为Base的构造函数正在尝试创建Derived,而后者将尝试调用Base的构造函数,这将尝试创建Derived ...
  • 即使递归被剪切(提供替代的Base构造函数,并将被调用的Derived构造函数调度到该非循环版本),并且Derived适合内存占用Base的{​​{1}}已经初始化的任何成员将重新初始化调用未定义的行为。例如,如果Base包含在内部分配和管理内存的属性,则其构造函数将被调用两次泄漏第一次调用中获取的资源。构造和破坏的物体数量分别不匹配。
  • 可能是DeadMG提及的 6 bajillion 号码的其他许多问题。

答案 3 :(得分:1)

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

答案 4 :(得分:0)

它试图声明DerivedClass类型的成员对象并将其指针强制转换为Baselass类型。 虽然它甚至没有编译。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

您的代码无法编译。

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