Search code examples
c++default-constructormember-initialization

Disable default class member initialization before constructor code


In C++, any member of a class which is not constructed in a member initialization list is default constructed before the containing class's constructor is executed. However, this appears to be very wasteful if that member variable is just going to get constructed anyway inside the constructor of the class it resides in.

I've provided an example below to clarify what I mean. Here, the Example class has a member variable x of type LargeIntimidatingClass. Using the member initialization list (the first constructor in Example) x is only constructed once. However, if x cannot be reasonably constructed using the member initialization list, it gets constructed twice!

//This class used as part of the example class further below
class LargeIntimidatingClass {
    // ...
    //many member variables and functions
    // ...

    LargeIntimidatingClass() {
        //Painfully expensive default initializer
    }

    LargeIntimidatingClass(int a, double b) {
        //Complicated calculations involving a and b
    }
};

//Here, this class has a LargeIntimidatingClass as a member variable.
class Example {
    LargeIntimidatingClass x;
    char c;

    //Basic member initialization list constructor. Efficient!
    Example(int a, double b, char c) : x(a,b), c(c) {}

    //What if the parameters to the LargeIntimidatingClass's constructor
    //need to be computed inside the Example's constructor beforehand?
    Example(std::string sophisticatedArgument) {
        //Oh no! x has already been default initialized (unnecessarily!)

        int a = something1(sophisticatedArgument);
        double b = something2(sophisticatedArgument);
        //x gets constructed again! Previous (default) x is totally wasted!
        x = LargeIntimidatingClass(a,b);

        c = something3(sophisticatedArgument);
    }
};

Yes, I realize that in this silly example you could write Example(string s) : x(f1(s),f2(s)), c(f3(s)) {}, but I'm sure you can imagine a situation where shoving a bunch of logic into a member initialization list is cumbersome (or even impossible).

Is it possible to disable a member variable's default constructor when it is not listed in the member initialization list?


Solution

  • You cannot disable the construction. All class members must be initialized before the body of the constructor is reached. That said, you can easily work around the problem. You can add a private static member function that gets a and b and returns a LargeIntimidatingClass from it like

    class Example {
        LargeIntimidatingClass x;
        char c;
        static LargeIntimidatingClass make_LargeIntimidatingClass(std::string sophisticatedArgument)
        {
            int a = something1(sophisticatedArgument);
            double b = something2(sophisticatedArgument);
            return LargeIntimidatingClass(a,b);
        }
        static char make_c(std::string sophisticatedArgument)
        {
            return something3(sophisticatedArgument);
        }
    public:
    
        //Basic member initialization list constructor. Efficient!
        Example(int a, double b, char c) : x(a,b), c(c) {}
    
        // now we use helpers to initialize in the member initialization list
        Example(std::string sophisticatedArgument) : x(make_LargeIntimidatingClass(sophisticatedArgument), c(make_c(sophisticatedArgument) {
            //now everything is initialized correctly
        }
    };