Is there a way to late-initialize a member variable (a class) in C++?

linuxeasy picture linuxeasy · Jul 11, 2014 · Viewed 7.2k times · Source

I am coming from the Java background. I have the following program.

#include <string>
#include <iostream>

class First {
    public:
    First(int someVal): a(someVal) {

    }
    int a;
};

class Second {
    public:
    First first;
    Second()  {   // The other option would be to add default value as ": first(0)"
        first = First(123);

    }
};

int main()
{
    Second second;
    std::cout << "hello" << second.first.a << std::endl;
}

In class Second, I wanted to variable first to remain uninitialized until I specifically initialize it in Second()'s constructor. Is there a way to do it? Or am I just left with 2 options?:

  1. Provide a parameter-less constructor.
  2. Initialize it with some default value and later re-assign the required value.

I can't initialize first in the initializer-list with the right value, since the value is obtained after some operation. So, the actual required value for first is available in Second() constructor only.

Answer

Mooing Duck picture Mooing Duck · Jul 11, 2014

MY suggestion: Use a function:

private: static int calculate_first(int input) {return input*5;}
explicit Second(int input) : first(calculate_first(input)) {}

Base classes will be initialized in the order they're declared in the class inheritance list, and then members will be initialized in the order that they're listed in the class, so the calculation can depend on non-static member-variables and base classes if they have already been initialized.


Alternatively:

Default constructor, then reassign:

explicit Second(int input) { first = input*5; }

Dummy value, then reassign:

explicit Second(int input) : first(0) { first = input*5; }

Use boost::optional (or std::optional as of C++17):

boost::optional<First> first;
explicit Second(int input) { first = input*5; }

Use the heap:

std::unique_ptr<First> first;
explicit Second(int input) { first.reset(new First(input*5));}
Second(const Second& r) first(new First(*(r->first))) {}
Second& operator=(const Second& r) {first.reset(new First(*(r->first)));}

Placement new:

This is tricky and not suggested 
and worse in every way than boost::optional
So sample deliberately missing.
But it is an option.