madmax1
madmax1

Reputation: 267

How to properly initialize non-default-constructible class member?

Assume I define a class Foo, which does not implement a default constructor. In addition, I have a class Bar, which "owns" an instance of Foo:

class Foo() {
  private:
    int m_member;
  public:
    Foo( int value ) : m_member(value) { }
};

class Bar() {
  private:
    Foo m_foo;
  public:
    Bar( /* ... */ ) {
      int something;
      /* lots of code to determine 'something' */
      /* should initialize m_foo to 'Foo(something)' here */
    }
};

The code as shown won't run, since Bar is trying to call the default constructor of Foo.

Now what I am trying to do is to have the constructor of Bar first determine something and then pass the result to the constructor of Foo.

One way to solve this is to have Bar only own a reference/pointer to Foo and initialize it after m_something was determined. However, I'd like to avoid that to make clear that the lifetime of m_foo is completely dependent on the lifetime of the owning class.

Another way would be to implement a default constructor in Foo and set the value later, which I would also like to avoid, since any instance of Foo should have a valid value for it's member (at any time).

What is the proper way to implement this? Am I stuck with a reference/pointer here?

Upvotes: 5

Views: 506

Answers (2)

Petr
Petr

Reputation: 10007

Does this complex initialization code actually belong to Bar? It may be good to consider having a separate class to just do this initializing. Something like

class Bar {
  public:
    Bar(int param, Foo foo): m_foo(foo) {
        // do just some very simple calculations, or use only constructor initialization list
    }
  ...
}

class BarBuilder {
  public:
    BarBuilder(/*...*/) {
        // do all calculations, boiling down to a few parameters for Bar and Foo
       Foo foo(fooParameter);
       m_result = new Bar(barParameter, foo); // give Foo here explicitly
    }
    Bar getResult() { return *m_result; }
  private:
    Bar* m_result; // or better use unique_ptr  
}

This also opens the way to a full Builder pattern that might be useful in case, for example, you do not always need all that complex calculations.

This assumes all classes to be copy-constructible, but you may more-or-less easily modify it to support what you need.

Upvotes: 2

ForEveR
ForEveR

Reputation: 55897

The best idea will be to create helper function, that will calculate something and then just initialize m_foo in constructor initialized list.

class Bar {
  private:
    Foo m_foo;
  public:
    Bar( /* ... */ ) : m_foo(calculate_something()) {
    }
private:
    static int calculate_something()
    {
       int something = 0;
       // lot of code to calculate something
       return something;
    }
};

Upvotes: 12

Related Questions