Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

placement new to defer to a different constructor

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();
    }
}
like image 548
Jonathan Swinney Avatar asked Apr 19 '10 14:04

Jonathan Swinney


4 Answers

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 does new 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.

like image 193
AshleysBrain Avatar answered Nov 17 '22 00:11

AshleysBrain


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

like image 41
Goz Avatar answered Nov 17 '22 01:11

Goz


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 the this is offset (sometimes happens in multiple inheritance) it'll construct at the wrong address.

like image 1
deft_code Avatar answered Nov 17 '22 00:11

deft_code


You wouldn't be safe if you extended another class and that class had a destructor, for example

class Foo
{
    int* a;
public:
    Foo():a(new int)
    {

    }
    ~Foo(){delete a;}
}

class Bar:public Foo
{
    Bar()
    {
        // initialize things
    }

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

First Bar(int) calls Foo(), then it calls Bar() which also calls Foo(). The second time Foo() is called, it overwrites the pointer set up by the first call to Foo(), and the allocated memory is leaked.

like image 1
Ken Bloom Avatar answered Nov 17 '22 02:11

Ken Bloom