放置新的以推迟到不同的构造函数
这安全吗?我在实际实现中没有使用任何虚拟函数,但我很想相信即使我使用了,它仍然是安全的。
class Foo
{
Foo()
{
// initialize things
}
Foo( int )
{
new ( this ) Foo();
}
}
Is this safe? I'm not using any virtual functions in my actual implementation, but I'm tempted to believe that even if I was, it would still be safe.
class Foo
{
Foo()
{
// initialize things
}
Foo( int )
{
new ( this ) Foo();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
当您输入
Foo(int)
构造函数的左大括号时,所有类成员的构造函数都已被调用。如果您随后使用 new 位置强制调用另一个构造函数,则会覆盖该类的当前状态。这基本上意味着所有成员的构造函数都被调用两次 - 如果在其构造函数中执行了 new 操作,那么您就会泄漏该内容,并且您真的会非常非常地把事情搞砸! 您实际上正在构造两个对象,并且永远不会调用第一个对象的成员的析构函数,因为第二个对象会覆盖第一个对象的内存。换句话说,这是糟糕!不要这样做!
最常见的解决方法是使用某种初始化函数,并从两个构造函数中调用它。不过,这不会让您初始化 const 成员和其他必须位于初始值设定项列表中的成员。
By the time you enter the open curly brace of the
Foo(int)
constructor, all class members have had their constructor called. If you then force a call to another constructor with placement new, you're overwriting the current state of the class. This basically means all members have their constructors called twice - if something doesnew
in its constructor, you leak that content, and you will really, really mess things up! You're effectively constructing two objects, and the destructors for the members of the first object are never called, since the second object overwrites the memory of the first object.In other words it's BAD! Don't do it!!
The most common workaround is to use some kind of initialisation function, and call that from both constructors. This won't let you initialize const members and others that must be in the initializer list, though.
http://www.parashift.com/c++-faq- lite/ctors.html#faq-10.3
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3
我担心的一个问题是,如果 Foo 使用多重继承,您需要首先将
this
指针强制转换为最基类。否则,如果this
发生偏移(有时发生在多重继承中),它将在错误的地址处构造。One worry I have is if Foo uses multiple inheritance you'll need to cast the
this
pointer to the most base class first. Othewise if the thethis
is offset (sometimes happens in multiple inheritance) it'll construct at the wrong address.如果您扩展了另一个类并且该类具有析构函数,那么您将不安全,例如
首先
Bar(int)
调用Foo()
,然后它调用Bar()
也调用Foo()
。第二次调用Foo()
时,它会覆盖第一次调用Foo()
时设置的指针,并且分配的内存会泄漏。You wouldn't be safe if you extended another class and that class had a destructor, for example
First
Bar(int)
callsFoo()
, then it callsBar()
which also callsFoo()
. The second timeFoo()
is called, it overwrites the pointer set up by the first call toFoo()
, and the allocated memory is leaked.这里的关键问题是构造函数是特殊的 - 当您编写调用构造函数的构造时(例如使用 new 关键字创建对象),不仅执行构造函数主体,而且执行整个链首先构造对象。
因此,当您使用placement-new语法首先运行另一个构造函数时,C++会自动重新运行所有基类对象构造函数和所有成员变量构造函数,然后才调用另一个构造函数主体。有时你会没事,但很多时候你会遇到意想不到的行为。
The key problem here is that constructors are special - when you write a construct that calls a constructor (for example use
new
keyword to create an object) not only the constructor body is executed, instead the whole chain of objects is constructed first.So when you use placement-new syntax to run another constructor first C++ automagically reruns all the base class object constructors and all the member variables constructors and only then the other constructor body is invoked. Sometimes you'll be okay, but many times you will run into unexpected behavior.
看起来这个问题的最佳解决方案是创建一个不同的函数来进行初始化:
It looks like the best solution to this problem is to just create a different function to do the initialization:
正如其他人所说,这是一个坏主意,并且可能是一种破坏性的情况:如果您不
欢迎无限递归的土地怎么办?
As others said, is a bad idea, and as a possible destructive case: what if you do
welcome no the land of infinite recursion.