AdeleGoldberg
AdeleGoldberg

Reputation: 1339

Why cant we delay initialise a class member with a non default constructor?

I have a class like below:

#pragma once
#include <atomic>

class MyClassAnother {
public:
    MyClassAnother(int val) : m_val(val) {
    }

private:
    int m_val;
};

There is another class which holds an object to MyClassAnother

#pragma once
#include "MyClassAnother.hpp"

class MyClass {
public:
    MyClass() {

    }

    void Func() {
        anotherClassObject = MyClassAnother(2);
    }

private:
    MyClassAnother anotherClassObject;
};

And here is the main.cpp

#include "MyClass.hpp"
#include <iostream>

int main() {
   MyClass object;
}

Of course the program does not compile. And its because of the following error

error: constructor for 'MyClass' must explicitly initialize the member 'anotherClassObject' which does not have a default constructor

Question:
But why? Why can't I delay initialise the class member? Is the workaround to have a default constructor and delay initialise it with the real constructor later? Is it an anti pattern to do it this way then?

I know that this can be resolved by making MyClassAnother anotherClassObject a pointer. But I want to have MyClassAnother anotherClassObject as a member object or a reference member in this case.

Upvotes: 0

Views: 273

Answers (1)

Thomas
Thomas

Reputation: 181785

The constructor must guarantee that all members are properly constructed and initialized, and this one doesn't do that. What happens if you forget to call Func() and then access objcect.anotherClassObject?

Delayed initialization in general could be considered an anti-pattern, and goes against the RAII idiom, which states that object construction should succeed if and only if initialization of underlying resources (MyClassAnother in this case) succeeded. It's a good pattern to follow, because it prevents having unusable objects around because they failed to initialize properly, or because somebody forgot to perform their delayed initialization steps.

If MyClass objects are actually usable without a MyClassAnother instance, you can wrap the latter in an std::unique_pointer (C++11) or an std::optional (C++17).

If MyClass objects are not usable without a MyClassAnother instance, you need to pass that instance to the constructor, or create it in the constructor's initializer list.

Upvotes: 1

Related Questions