Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 531
madmax1 Avatar asked Oct 19 '15 09:10

madmax1


People also ask

How do you initialize a class member?

To initialize a class member variable, put the initialization code in a static initialization block, as the following section shows. To initialize an instance member variable, put the initialization code in a constructor.

How do you initialize a class member in C++?

There are two ways to initialize a class object: Using a parenthesized expression list. The compiler calls the constructor of the class using this list as the constructor's argument list. Using a single initialization value and the = operator.

Are class members default initialized C++?

for built-in type, it is initialized to 0. for class type, it is default initialized.

What is default constructible C++?

A default constructible class is a class that has a default constructor (either its implicit constructor or a custom defined one). The is_default_constructible class inherits from integral_constant as being either true_type or false_type, depending on whether T is default constructible.


2 Answers

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;
    }
};
like image 196
ForEveR Avatar answered Oct 20 '22 10:10

ForEveR


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.

like image 32
Petr Avatar answered Oct 20 '22 10:10

Petr