11

这安全吗?我在实际实现中没有使用任何虚函数,但我很想相信即使我使用了,它仍然是安全的。

class Foo
{
    Foo()
    {
        // initialize things
    }

    Foo( int )
    {
         new ( this ) Foo();
    }
}
4

7 回答 7

13

当你进入构造函数的大括号时Foo(int),所有类成员都已经调用了它们的构造函数。如果您随后使用放置 new 强制调用另一个构造函数,则您将覆盖该类的当前状态。这基本上意味着所有成员的构造函数都被调用了两次——如果new在它的构造函数中发生了某些事情,你就会泄漏该内容,你真的会搞砸事情! 您正在有效地构造两个对象,并且永远不会调用第一个对象成员的析构函数,因为第二个对象会覆盖第一个对象的内存。

换句话说,它很糟糕!不要这样做!

最常见的解决方法是使用某种初始化函数,并从两个构造函数中调用它。但是,这不会让您初始化 const 成员和其他必须在初始化列表中的成员。

于 2010-04-19T14:34:48.900 回答
3

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3

于 2010-04-19T14:30:55.150 回答
1

我担心的一个问题是,如果 Foo 使用多重继承,您需要首先将this指针转换为最基类。否则,如果this偏移量(有时发生在多重继承中),它将在错误的地址处构造。

于 2010-04-19T14:32:34.870 回答
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()which也调用Foo()。第二次Foo()调用,它覆盖了第一次调用设置的指针Foo(),分配的内存泄漏。

于 2010-04-19T14:33:44.507 回答
1

这里的关键问题是构造函数是特殊的——当你编写一个调用构造函数的构造(例如使用new关键字来创建一个对象)时,不仅会执行构造函数主体,而是首先构造整个对象链。

因此,当您使用placement-new 语法首先运行另一个构造函数时,C++ 会自动重新运行所有基类对象构造函数和所有成员变量构造函数,然后才调用另一个构造函数主体。有时你会没事,但很多时候你会遇到意想不到的行为。

于 2010-04-19T14:33:47.380 回答
1

看起来这个问题的最佳解决方案是创建一个不同的函数来进行初始化:

class Foo
{
    inline void nullify()
    {
        // initialize things
    }

    Foo()
    {
        nullify();
    }

    Foo( int )
    {
        nullify();
    }
}
于 2010-04-19T14:40:15.017 回答
0

正如其他人所说,这是一个坏主意,并且作为一个可能的破坏性案例:如果你这样做

class Foo
{
    Foo()
    {
        // initialize things
    }

    Foo( int bar )
    {
         new ( this ) Foo(bar);
    }
}

欢迎没有无限递归的土地。

于 2017-02-09T22:58:30.447 回答