这样安全吗?我在实际实现中没有使用任何虚函数,但我很想相信即使我是,它仍然是安全的。
class Foo
{
Foo()
{
// initialize things
}
Foo( int )
{
new ( this ) Foo();
}
}
答案 0 :(得分:13)
当您输入Foo(int)
构造函数的开放大括号时,所有类成员都已调用其构造函数。如果然后强制调用另一个带有placement new的构造函数,那么你将覆盖该类的当前状态。这基本上意味着所有成员都有两次调用它们的构造函数 - 如果它的构造函数中有new
,那么你泄漏了那些内容,你真的会把事情弄得一团糟! 您正在有效地构建两个对象,并且第一个对象的成员的析构函数永远不会被调用,因为第二个对象会覆盖第一个对象的内存。
换句话说,它是 BAD !不要这样做!!
最常见的解决方法是使用某种初始化函数,并从两个构造函数中调用它。但是,这不会让你初始化const成员和必须在初始化列表中的其他成员。
答案 1 :(得分:3)
答案 2 :(得分:1)
我担心的一个问题是,如果Foo使用多重继承,您需要先将this
指针强制转换为最基类。如果this
被偏移(有时在多重继承中发生),它将构造在错误的地址。
答案 3 :(得分:1)
如果你扩展另一个类并且该类有一个析构函数,例如
,那么你就不安全了class Foo
{
int* a;
public:
Foo():a(new int)
{
}
~Foo(){delete a;}
}
class Bar:public Foo
{
Bar()
{
// initialize things
}
Bar( int )
{
new ( this ) Foo();
}
}
首先Bar(int)
来电Foo()
,然后调用Bar()
并调用Foo()
。第二次调用Foo()
时,它会覆盖第一次调用Foo()
时设置的指针,并且分配的内存被泄露。
答案 4 :(得分:1)
这里的关键问题是构造函数是特殊的 - 当你编写一个调用构造函数的构造时(例如使用new
关键字创建一个对象),不仅构造函数体被执行,而是整个链首先构造对象。
因此,当您使用placement-new语法运行另一个构造函数时,首先C ++会自动重新运行所有基类对象构造函数和所有成员变量构造函数,然后才会调用其他构造函数体。有时你会没事的,但很多时候你会遇到意想不到的行为。
答案 5 :(得分:1)
看起来这个问题的最佳解决方案是创建一个不同的函数来进行初始化:
class Foo
{
inline void nullify()
{
// initialize things
}
Foo()
{
nullify();
}
Foo( int )
{
nullify();
}
}
答案 6 :(得分:0)
正如其他人所说,这是一个坏主意,并且作为一种可能的破坏性案例:如果你做了
class Foo
{
Foo()
{
// initialize things
}
Foo( int bar )
{
new ( this ) Foo(bar);
}
}
欢迎没有无限递归的土地。