Alex Meiburg
Alex Meiburg

Reputation: 656

How to initialize member object when parameters aren't available at time of initializer list?

Current structure is something like

class B {
  //no default constructor
  //this is a class in a third-party library, can't be modified
  B(Lots ofData, AndOther arguments);
}

class A {
  B b;

  A(some_parameters){
     //Do a lot of stuff with those parameters, make Results
     B b(Results, Results); //ERROR
  }
}

So, I need to call the constructor on B, but I don't have the information early enough to do it in the initializer list. How do I call the constructor on B later? Because B doesn't have a trivial constructor, I can't exactly initialize with some dumb defaults and overwrite it later, either.

I can't change the B class.

Upvotes: 1

Views: 63

Answers (2)

Jarod42
Jarod42

Reputation: 217135

Another alternative in C++11 is delegating constructor, something similar to:

Result foo(Parameters some_parameters)
{
    //Do a lot of stuff with those parameters, make Results
}

class A
{
    B b;
public:    
    A(Parameters some_parameters) : A(foo(some_parameters)){}

private:
    A(Result result) : b(Results, Results) {}
};

Upvotes: 2

Michael Kenzel
Michael Kenzel

Reputation: 15943

If B has a copy/move constructor, you could simply make a function that returns you a B and use that to initialize the member like so:

B makeB(some_parameters) {
    //Do a lot of stuff with those parameters, make Results
    return B(Results, Results);
}

class A {
    B b;

    A(some_parameters)
      : b(makeB(some_parameters))
    {
    }
};

If copying/moving a B into your member is not an option, then one simple solution would be to just allocate the B object dynamically. That way you could move all the "lots of stuff, make Results" into a function

#include <memory>

std::unique_ptr<B> makeB(some_parameters) {
    //Do a lot of stuff with those parameters, make Results
    return std::make_unique<B>(Results, Results);
}

class A {
    std::unique_ptr<B> b;

    A(some_parameters)
      : b(makeB(some_parameters))
    {
    }
};

If you want your B to live directly inside the A object, you could use an std::optional<B> or an unnamed union in which you emplace the object at a later point:

#include <memory>

class A {
    union {
        B b;
    };

    A(some_parameters) {
        //Do a lot of stuff with those parameters, make Results
        new (&b) B(Results, Results);
    }

    ~A() {  // this is only needed if B has a non-trivial destructor
        b.~B();
    }
};

Upvotes: 3

Related Questions