Why use an initialization method instead of a constructor?

C++ConstructorInitialization

C++ Problem Overview


I just got into a new company and much of the code base uses initialization methods instead of constructors.

struct MyFancyClass : theUberClass
{
    MyFancyClass();
    ~MyFancyClass();
    resultType initMyFancyClass(fancyArgument arg1, classyArgument arg2, 
                                redundantArgument arg3=TODO);
    // several fancy methods...
};

They told me that this had something to do with timing. That some things have to be done after construction that would fail in the constructor. But most constructors are empty and I don't really see any reason for not using constructors.

So I turn to you, oh wizards of the C++: why would you use an init-method instead of a constructor?

C++ Solutions


Solution 1 - C++

Since they say "timing", I guess it's because they want their init functions to be able to call virtual functions on the object. This doesn't always work in a constructor, because in the constructor of the base class, the derived class part of the object "doesn't exist yet", and in particular you can't access virtual functions defined in the derived class. Instead, the base class version of the function is called, if defined. If it's not defined, (implying that the function is pure virtual), you get undefined behavior.

The other common reason for init functions is a desire to avoid exceptions, but that's a pretty old-school programming style (and whether it's a good idea is a whole argument of its own). It has nothing to do with things that can't work in a constructor, rather to do with the fact that constructors can't return an error value if something fails. So to the extent that your colleagues have given you the real reasons, I suspect this isn't it.

Solution 2 - C++

Yes I can think of several, but generally it's not a good idea.

Most of the times the reason invoked is that you only report errors through exceptions in a constructor (which is true) whereas with a classic method you can return an error code.

However in properly designed OO-code the constructor is responsible for establishing the class invariants. By allowing a default constructor, you allow an empty class, thus you have to modify the invariants so that is accepted both the "null" class and the "meaningful" class... and each use of the class must first ensure that the object has been properly built... it's crass.

So now, let's debunk the "reasons":

  • I need to use a virtual method: use the Virtual Constructor idiom.
  • There is a lot of work to be done: so what, the work will be done anyway, just do it in the constructor
  • The setup may fail: throw an exception
  • I want to keep the partially initialized object: use a try/catch within the constructor and set the error cause in an object field, don't forget to assert at the beginning of each public method to make sure the object is usable before trying to use it.
  • I want to reinitialize my object: invoke the initialization method from the constructor, you'll avoid duplicate code while still having a fully initialized object
  • I want to reinitialize my object (2): use operator= (and implement it using the copy and swap idiom if the compiler generated version does not suit your need).

As said, in general, bad idea. If you really want to have "void" constructor, make them private and use Builder methods. It's as efficient with NRVO... and you can return boost::optional<FancyObject> in case the construction failed.

Solution 3 - C++

Others have listed lots of possible reasons (and proper explanations of why most of these are generally not a good idea). Let me post one example of a (more or less) valid use of init methods, which actually has to do with timing.

In a previous project, we had lots of Service classes and objects, each of which were part of a hierarchy, and cross referencing each other in various ways. So typically, for creating a ServiceA, you needed a parent service object, which in turn needed a service container, which already depended on the presence of some specific services (possibly including ServiceA itself) at initialization time. The reason was that during initialization, most of the services registered itself with other services as listeners to specific events, and/or notified other services about the event of successful initialization. If the other service did not exist at the time of notification, the registration did not happen, thus this service would not receive important messages later, during the usage of the application. In order to break the chain of circular dependencies, we had to use explicit initialization methods separate from constructors, thus effectively making global service initialization a two-phase process.

So, although this idiom should not be followed in general, IMHO it has some valid uses. However, it is best to limit its usage to the minimum, using constructors whenever possible. In our case, this was a legacy project, and we didn't yet fully understand its architecture. At least the usage of init methods was limited to the service classes - regular classes were initialized via constructors. I believe there might be a way to refactor that architecture to eliminate the need for service init methods, but at least I did not see how to do it (and to be frank, we had more urgent issues to deal with at the time I was part of the project).

Solution 4 - C++

Two reasons I can think of off the top of my head:

  • Say creating an object involves lots and lots of tedious work that can fail in lots and lots of horrible and subtle ways. If you use a short constructor to set up rudamentary things that won't fail, and then have the user call an initialization method to do the big job, you can at least be sure that you have some object created even if the big job fails. Maybe the object contains information about precisely what way the init failed, or maybe it's important to keep unsuccessfully initialized objects around for other reasons.
  • Sometimes you might want to reinitialize an object long after it has been created. In this way, it's just a matter of calling the initialization method again without destroying and recreating the object.

Solution 5 - C++

One more use of such initialization can be in object pool. Basically you just request the object from the pool. The pool will have already some N objects created which are blank. It's the caller now which can call any method he/she likes to set the members. Once caller has done with the object it will tell the pool to destory it. The advantage is until the object is being used the memory will be saved, and the caller can use it's own suitable member method of initializing the object. An object may be serving a lot of purpose but the caller may not need all, and also may not need to initialize all the member of the objects.

Typically think of database connections. A pool can have bunch of connection object, and the caller can fill the username, password etc.

Solution 6 - C++

init() function are good when your compiler doesn't support exceptions, or your target application cannot use a heap (exception are usually implemented using a heap to create and destroy them).

init() routines are also useful when the order of construction needs to be defined. That is to say, if you globally allocate objects, the order in which the constructor is invoked is not defined. For instance:

[file1.cpp]
some_class instance1; //global instance

[file2.cpp]
other_class must_construct_before_instance1; //global instance

The standard provides no guarantee that must_construct_before_instance1's constructor will be invoked before instance1's constructor. When it's tied to hardware, order in which things initialize can be crucial.

Solution 7 - C++

And also I like to attach a code sample to answer #1 --

Since also msdn says :

> When a virtual method is called, the > actual type that executes the method > is not selected until run time. When a > constructor calls a virtual method, it > is possible that the constructor for > the instance that invokes the method > has not executed.

Example : The following example demonstrates the effect of violating this rule. The test application creates an instance of DerivedType, which causes its base class (BadlyConstructedType) constructor to execute. BadlyConstructedType's constructor incorrectly calls the virtual method DoSomething. As the output shows, DerivedType.DoSomething() executes, and does so before DerivedType's constructor executes.

using System;

namespace UsageLibrary
{
    public class BadlyConstructedType
    {
        protected  string initialized = "No";
        
        public BadlyConstructedType()
        {
            Console.WriteLine("Calling base ctor.");
            // Violates rule: DoNotCallOverridableMethodsInConstructors.
            DoSomething();
        }
        // This will be overridden in the derived type.
        public virtual void DoSomething()
        {
            Console.WriteLine ("Base DoSomething");
        }
    }
    
    public class DerivedType : BadlyConstructedType
    {
        public DerivedType ()
        {
            Console.WriteLine("Calling derived ctor.");
            initialized = "Yes";
        }
        public override void DoSomething()
        {
            Console.WriteLine("Derived DoSomething is called - initialized ? {0}", initialized);
        }
    }
 
    public class TestBadlyConstructedType
    {
        public static void Main()
        {
            DerivedType derivedInstance = new DerivedType();
        }
    }
}

Output :

Calling base ctor.

Derived DoSomething is called - initialized ? No

Calling derived ctor.

Solution 8 - C++

More of a special case: If you create a listener, you might want to make it register itself somewhere (such as with a singleton or GUI). If you do that during its constructor, it leaks a pointer/reference to itself which is not yet safe, since the constructor has not completed (and might even fail completely). Assume the singleton that collects all listeners and sends them events when things happen receives and event, and then loops through its list of listeners (one of them is the instance we are talking about), to send them each a message. But this instance is still mid-way in its constructor, so the call can fail in all kinds of bad ways. In this case, it makes sense to have registration in a separate function, which you obviously do not call from the constructor itself (that would defeat the purpose entirely), but from the parent object, after construction has completed.

But that is a specific case, not the general one.

Solution 9 - C++

It's useful for doing resource management. Say you have classes with destructors to automatically deallocate resources when the object's lifetime is over. Say you also have a class that holds these resource classes, and you initiate them in the constructor of this upper class. What happens when you use the assignment operator to initiate this higher class? Once the contents are copied, the old higher class becomes out of context, and the destructors are called for all the resource classes. If these resource classes have pointers that were copied during assignment, then all these pointers are now bad pointers. If you instead initiate the resource classes in a seperate init function in the higher class, you completely bypass the resource class' destructor from ever being called, because the assignment operator never has to create and delete these classes. I believe this is what was meant by the "timing" requirement.

Solution 10 - C++

A few more cases:

COOKING ARGS

A constructor can't call another constructor, but an init method can call another init.

For instance say we have a initializer that takes a list of conventional args. We have another initializer that takes a dictionary of name=value pairs. The second can query the dictionary for the arguments the first initializer accepts and call the first with them.

This is fine when the initializers are an init methods, but not when the initializers are constructors.

CHICKEN OR EGG

We might have a car class whose initializer must have a pointer to a motor object, and the motor class initializer must have a pointer to its car object. This is simply impossible with constructors, but trivial with init methods.

BREAKING UP ARG LIST

There may be a huge number of args that could be specified but don't need to be (perhaps the default values suffice, or perhaps some parameters are only needed depending on values for other parameters). We may wish to have several initializers instead of a single one.

Again, it's simply impossible to break up a constructor, but trivial to break up an initializer.

Solution 11 - C++

You use an initialisation method instead of the constructor if the initialiser needs to be called AFTER the class has been created. So if class A was created as:

A *a = new A;

and the initisalizer of class A required that a be set, then obviously you need something like:

A *a = new A;
a->init();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbastibeView Question on Stackoverflow
Solution 1 - C++Steve JessopView Answer on Stackoverflow
Solution 2 - C++Matthieu M.View Answer on Stackoverflow
Solution 3 - C++Péter TörökView Answer on Stackoverflow
Solution 4 - C++gsprView Answer on Stackoverflow
Solution 5 - C++Manoj RView Answer on Stackoverflow
Solution 6 - C++TRISAbitsView Answer on Stackoverflow
Solution 7 - C++TarikView Answer on Stackoverflow
Solution 8 - C++Kajetan AbtView Answer on Stackoverflow
Solution 9 - C++ChristopherView Answer on Stackoverflow
Solution 10 - C++Swiss FrankView Answer on Stackoverflow
Solution 11 - C++Alexander RaffertyView Answer on Stackoverflow