views:

938

answers:

13

I want to ask you for your best practices regarding constructors in C++. I am not quite sure what I should do in a constructor and what not.

Should I only use it for attribute initializations, calling parent constructors etc.? Or might I even put more complex functions into them like reading and parsing configuration data, setting up external libraries a.s.o.

Or should I write special functions for this? Resp. init() / cleanup()?

What are the PRO's and CON's here?

I figured out yet that for example I can get rid of shared pointers when using init() and cleanup(). I can create the objects on the stack as class attributes and initialize it later while it is already constructed.

If I handle it in the constructor I need to instantiate it during runtime. Then I need a pointer.

I really don't know how to decide.

Maybe you can help me out?

+2  A: 

Well, «constructor» comes from construction, building, setting up. So there's where all initialization happens. Whenever you instance a class, use the constructor to ensure that everything is done in order to make the new object workable with.

Júlio Santos
A: 

Some libraries are easier to work with if you have init() functions instead of constructors.

However, @DumbCoder comment is really appropriate.

The FQA argues that problems like knowing when you can or can not the "this" pointer in a constructor goes away if you use init functions instead.

Amigable Clark Kant
“No discussion is complete without …” – That’s it, I’m calling Godwin’s Law on the FQA. For details, see my reply to your comment below the question itself. – I’m somewhat suspicious of your repeated use of the FQA as an argument *without you giving any details, nor explanations*. What exactly are you referring to in the FQA? Where are the salient points relating to the question? In fact, **nothing** on the page you linked to has **any** connection to the question. (Except a *very* brief mention when yelling angrily at exceptions, without saying what is actually wrong about them.)
Konrad Rudolph
@Konrad Rudolph, you are right, after a fashion. I will be a better person...
Amigable Clark Kant
+4  A: 

A constructor is expected to create an object that can be used from the word go. If for some reason it is not able to create a usable object, it should throw an exception and be done with it. So, all supplementary methods/functions that are necessary for an object to work properly should be called from the constructor (unless you want to have lazy-loading like features)

blahster
+14  A: 
  • Don't call delete this or the destructor in the constructor.
  • Don't use init()/cleanup() members. If you have to call init() every time you create an instance, everything in init() should be in the constructor. The constructor is meant to put the instance into a consistent state which allows any public member to be called with a well-defined behavior. Similarly for cleanup(), plus cleanup() kills RAII. (However, when you have multiple constructors, it's often useful to have a private init() function that's called by the them.)
  • Doing more complex things in constructors is okay, depending on the classes' intended use and your overall design. For example, it wouldn't be a good idea to read a file in the constructor of some kind of Integer or Point class; users expect those to be cheap to create. It's also important to consider how file-accessing constructors will impact your ability to write unit tests. The best solution is usually to have a constructor that just takes the data that it needs to construct the members and write a non-member function that does the file parsing and returns an instance.
Steve M
-1: no, doing more complex things is **not** okay. Using polymorphism in a constructor or in a destructor is often bound to **fail**. See my example below.
Stephane Rolland
"Don't call `delete this` in the constructor" — haven't you heard of Resource Acquisition Is Invalidation?
Potatoswatter
+1. I disagree with "no `init()`", though. That essentially argues against any code factoring in constructors. `init` should not replace the member initializer list, but one of Stroustrup's favorite C++0x features, nonstatic member initializers, gets the best of both worlds.
Potatoswatter
@Stephane: I was going by Benjamin's usage of "complex": things that will take a while. The semantics of polymorphic functions in constructors are pretty simple, IMO. But, it's a good point to bring up anyhow.
Steve M
@Potatoswatter: I agree and even ninja-edited that into my answer.
Steve M
@Steve M, ok for the semantics ;-), but any complex function may happen to call a function that is virtual, or that will become virtual much later in the development.
Stephane Rolland
@Steve M, as franji suggested below, the call tree of any complex function called in a constructor and destructor, must be checked not to rely on calls of virtual functions. That's why I really don't agree with your statement `Doing more complex things in constructors is okay`: That's wrong.
Stephane Rolland
I side with FQA on the matter: http://yosefk.com/c++fqa/ctors.html
Amigable Clark Kant
On what matter? That he thinks that nobody should ever use any C++ feature?
Steve M
I've never heard of calling "delete this" in the constructor. What would be the motivation for this?
Ben
I don't think that there would be any motivation ;).
Steve M
+14  A: 

The most common mistake to do in a constructor as well as in a destructor, is to use polymorphism. Polymorphism often does not work in constructors !

e.g.:

class A
{
public:
    A(){ doA();} 
    virtual void doA(){};
}

class B : public A
{
public:
    virtual void doA(){ doB();};
    void doB(){};   
}


void testB()
{
    B b; // this WON'T call doB();
}

this is because the object B is not yet constructed while performing the constructor of the mother class A... thus impossible for it to call the overriden version of void doA();

Ben, in the comments below, has asked me for an example where polymorphism will work in constructors.

e.g.:

class A
{
public: 
    void callAPolymorphicBehaviour()
    {
        doOverridenBehaviour(); 
    }

    virtual void doOverridenBehaviour()
    {
        doA();
    }

    void doA(){}
};

class B : public A
{
public:
    B()
    {
        callAPolymorphicBehaviour();
    }

    virtual void doOverridenBehaviour()
    {
        doB()
    }

    void doB(){}
};

void testB()
{
   B b; // this WILL call doB();
}

This time, the reason behind is: at the time the virtual function doOverridenBehaviour() is invoked, the object b is already initialized (but not yet constructed), this means that its virtual table is initialized, and thus can perform polymorphism.

Stephane Rolland
+1 You can't emphasize that hard enough!
Helper Method
Did you mean to inherit B from A as in `class B : public A`?
ArunSaha
@ArunSaha, yep you're right ;-), thanx for the remark, I have edited.
Stephane Rolland
If you happen to need to call a specific override of a virtual method, I think it's okay to call the method statically from B's ctor, e.g. A::DoA() or B::DoA().
franji1
One caveat of calling ANY non-virtual method from a ctor, make sure there are no virtual "this" calls within the call tree. For example, my example above of statically calling a virtual method - but if A::DoA() calls a virtual method, you're still hosed as discussed in this answer.
franji1
@franji that why I did -1 at the Steve M's answer saying that anything else complex is okay to be done in a constructor. As you said, the call tree must be checked not to rely on any virtual call. And I have had this bug several times, and each times it has been really really hard to track it down.
Stephane Rolland
@Stephane Rolland: You say, "Polymorphism often does not work in constructors!" This implies that it does work in some cases. Can you explain?
Ben
@Ben, I have edited my answer and added a second example, where in that case, the polymorphism is in action. Just ask me again if ever my second example is not enough clear. ;-).
Stephane Rolland
+12  A: 

Complex logic and constructor do not always mix well, and there are strong proponents against doing heavy work in a constructor (with reasons).

The cardinal rule is that the constructor should yield a fully usable object.

class Vector
{
public:
  Vector(): mSize(10), mData(new int[mSize]) {}
private:
  size_t mSize;
  int mData[];
};

It does not mean a fully initialized object, you may defer some initialization (think lazy) as long as the user does not have to think about it.

class Vector
{
public:
  Vector(): mSize(0), mData(0) {}

  // first call to access element should grab memory

private:
  size_t mSize;
  int mData[];
};

If there is heavy work to be done, you might choose to proceed with a builder method, that will do the heavy work prior to calling the constructor. For example, imagine retrieving settings from a database and building a setting object.

// in the constructor
Setting::Setting()
{
  // connect
  // retrieve settings
  // close connection (wait, you used RAII right ?)
  // initialize object
}

// Builder method
Setting Setting::Build()
{
  // connect
  // retrieve settings

  Setting setting;
  // initialize object
  return setting;
}

This builder method is useful if postponing the construction of the object yields a significant benefit. From example if the objects grab a lot of memory, postponing the memory acquisition after tasks that are likely to fail may not be a bad idea.

This builder method implies Private constructor and Public (or friend) Builder. Note that having a Private constructor imposes a number of restrictions on the usages that can be done of a class (cannot be stored in STL containers, for example) so you might need to merge in other patterns. Which is why this method should only be used in exceptional circumstances.

You might wish to consider how to test such entities too, if you depend on an external thing (file / DB), think about Dependency Injection, it really helps with Unit Testing.

Matthieu M.
+1 for keeping simple mechanisms in constructors. But suggesting the use of RAII could be worth it also though not that simple.
Stephane Rolland
The problem with calling init() methods on a lazy basis is that you have to make absolutely sure they get called before use.
David Thornley
@David: I agree, and the simpler the better. I suggested it mainly for completeness.
Matthieu M.
+1 for "The cardinal rule is that the constructor should yield a fully usable object."
Viktor Sehr
+1  A: 

I would rather ask:

What all to do in the constructor?

and anything not covered above is answer to the OP's question.

I think the one and only purpose of the constructor is to

  1. initialize all the member variables to a known state, and

  2. allocate resources (if applicable).

The item #1 sounds so simple, yet I see that to be forgotten/ignored on regular basis and only to be reminded by a static analysis tool. Never underestimate this (pun intended).

ArunSaha
+3  A: 

Simple answer: it depends.

When designing your software you should might want to program via the RAII principle ("Resource Acquisition is initialization"). This means (among other things) that the object itself is responsible for its resources, and not the caller. Also, you might want to familiarize yourself with exception safety (in their different degrees).

For example, consider:

void func() {
    MyFile f("myfile.dat");
    doSomething(f);
}

If you design the class MyFile in the way, that you can be sure before doSomething(f) that f is initialized, you save a lot of trouble checking for that. Also, if you release the ressources held by f in the destructor, i.e. close the file handle, you are on the safe side and it is easy to use.

In this specific case you can use the special properties of constructors:

  • If you throw an exception from the constructor to its outside world, the object will not be created. This means, the destructor will not be called and the memory will be freed immediately.
  • A constructor must be called. You can not force the user to use any other function (except the destructor), only by convention. So, if you want to force the user to initialize your object, why not via the constructor?
  • If you have any virtual methods, you should not call those from inside the constructor, unless you know what you are doing -- you (or later users) might get surprised why the virtual overriding method is not called. Best not to confuse anyone.

A constructor must leave your object in a usable state. And because it is aways wise to make it difficult to use your API wrong, the best thing to do is make it easy to be used correct (sic to Scott Meyers). Doing initialization inside the constructor should be your default strategy -- but there are always exceptions, of course.

So: It is a good way to use constructors for initialization. It is not always possible, for example GUI frameworks often need to be constructed, then initialized. But if you design your software completely in this direction, you can save a lot of trouble.

towi
+3  A: 

You MAY throw from a constructor, and it is often the better option than creating a zombie object, i.e. an object that has a "failed" state.

You should, however, never throw from a destructor.

The compiler WILL know what order the member objects are constructed - the order they appear in the header. The destructor will however not be called as you said, which means if you are calling new multiple times within a constructor you cannot rely on your destructor calling the deletes for you. If you put them into smart pointer objects that is not a problem as these objects will be deleted. If you want them as raw pointers then put them temporarily into auto_ptr objects until you know your constructor will no longer throw, then call release() on all your auto_ptrs.

CashCow
+1  A: 

You can do what you want to do, but use constructor for that purpose for what it's call - create object. and if for that need to call others methods, that's Ok. just follow one rule - don't make it complex more than it's need. Good practice is to do constructor as simple as possible, but that not means that you need just initialize members.

Dainius
A very vague answer, I can not make myself neither upvote nor downvote.
Amigable Clark Kant
+1  A: 

I think the most important thing is a bit of common sense! There's lots of talk about do's and dont's - all well and good, but the key point to consider is how your object will be used. For example,

  1. how many instances of this object will be created? (are they held in containers for example?)
  2. how often are they created and destroyed? (loops?)
  3. how big is it?

If this object is a single instance, that is constructed at the start and the construction is not in the critical path - why not do the heavy work in the constructor (as long as you use exceptions appropriately, it may even make more sense)? If on the other hand, it's a very light weight object that is created and destroyed in a loop for a short period of time - try do as little as possible (aside from initializing the members, for example) (functors are a very good example of this...)

There are advantages to having a two phase load (or whatever), but main disadvantage is forgetting to call it - how many of us have done that?? :)

So, my tuppence is, don't stick to a hard and fast rule, look carefully at how your object is to be used, and then design it to suit!

Nim
+1  A: 

A constructor is used to construct an object - nothing more and nothing less. You need to do whatever it takes to establish the class invariants within a constructor and how complex that is it really depends on the type of the object being initialized.

Separate init() functions are a good idea only if for some reason you can't use exceptions.

Nemanja Trifunovic
+2  A: 

From The C++ Programming Language:

The use of functions such as init() to provide initialization for class objects is inelegant and errorprone. Because it is nowhere stated that an object must be initialized, a programmer can forget to do so – or do so twice (often with equally disastrous results). A better approach is to allow the programmer to declare a function with the explicit purpose of initializing objects. Because such a function constructs values of a given type, it is called a constructor.

I usually consider the following rule when designing a class: I must be able to use any method of the class safely after the constructor has executed. Safe here means you could always throw exceptions if the object's init() method has not been called, but I prefer to have something that is actually usable.

For instance, class std::string might not allocate any memory when you use the default constructor because most methods (i.e. begin() and end()) would work correctly if both return null pointers, and c_str() does not necessarily return the current buffer for other desing reasons, therefore it has to be prepared to allocate memory at any time. Not allocating memory in this case still leads to a perfectly usable string instance.

Conversely, use of RAII in scoped guards for mutex locks is an example of a constructor that may execute for an arbitrarily long time (until the lock's owner releases it) yet is still commonly accepted as good practice.

In any case, lazy initialization may be done in safer ways than using an init() method. One way is to use some intermediate class that captures all parameters to the constructor. Another is to use the builder pattern.

André Caron