morokei
morokei

Reputation: 31

C++: How to call member constructor outside the initializer list during object construction?

I want to call a constructor of a member object in the owners constructor, but can not construct the member object in the initializer-list because of dependencies. How can I call the constructer after my initializations? I would really like to not use an init method

Upvotes: 3

Views: 1502

Answers (4)

Jarod42
Jarod42

Reputation: 218333

want to call a constructor of a member object in the owners constructor, but can not construct the member object in the initializer-list because of dependencies

You might modify your class to have correct dependency order, and maybe use delegating constructor:

So turning:

struct S
{
    S(/*..*/) : /*m1(data), m2(data),*/ data(/*..*/) // Issue, m1, m2 constructed before data
    {
        ComplexData2 data2 = Query();

        m1.init(data, data2.someField1); // Doesn't like init method
        m2.init(data, data2.someField2); // Doesn't like init method
    } 

    Member1 m1; // Cannot be const with init method :/
    Member2 m2; // Cannot be const with init method :/
    ComplexData data;
};

into

struct S
{
    S(/*..*/) : S(Query() /*, ..*/) {}

// private: // probably private
    S(const ComplexData2& data2 /*, ..*/) :
        data(/*..*/),
        m1(data, data2.someField1),
        m2(data, data2.someField2)
    {
    } 

public:
    ComplexData data; // Before m1, m2 for dependencies.
    /*const*/ Member1 m1; // Can be const
    /*const*/ Member2 m2; // Can be const
};

Upvotes: 0

joe_chip
joe_chip

Reputation: 2558

You have two options: either use dynamic storage, or placement new.

The first one is obvious (as pointed out in comments, you can use unique_ptr). If you want to avoid this, you might try placement new with std::aligned_union as storage:

class SomeClass { ... };

class Owner
{
public:
    Owner()
    {
        m_ptr = new(&m_storage) SomeClass();
    }

    ~Owner()
    {
         m_ptr->~SomeClass();
    } 

private:
    std::aligned_union<0, SomeClass> m_storage;
    SomeClass* m_ptr;
};

Note: in this case, you are responsible to calling destructor of the object, as shown above.

You can wrap m_ptr with a unique_ptr (with a deleted which only calls a destructor) to avoid this:

struct DtorDeleter 
{ 
    template<typename T>
    void operator ()(T* ptr) { ptr->~T(); } 
};

std::unique_ptr<SomeClass, DtorDeleter> m_ptr; // no need to call destructor manually

Upvotes: 3

geza
geza

Reputation: 30020

You can use an union for this (C++11 needed):

#include <new>

class Foo {
    public:
        Foo(int a) { }
};

class Bar {
    public:
        Bar() {
            new(&m_foo) Foo(42); // call the constructor
            // you can use m_foo from this point
        }

        ~Bar() {
            m_foo.~Foo(); // call the destructor
        }

    private:
        union { // anonymous union
            Foo m_foo;
        };
};

Note that you need to explicitly call the destructor of m_foo at ~Bar().

Upvotes: 0

gsamaras
gsamaras

Reputation: 73444

No.

You cannot call the constructor of a member class outside the initializer list.

PS: Even if you don't call it yourself in the initializer list, then the compiler will do it implicitly.


If you cannot call it in the initializer list, and you don't want to use an init-like method, then re-think your design/approach.

Upvotes: 5

Related Questions