views:

191

answers:

10

I'm reviewing some code and I'm seeing a lot of this:

class Foo
{
public:
  Foo()
  {
    // 'nuffin
  }

  void init()
  {
    // actual construction code
  }
} ;

The only advantage I can see is if you create a Foo without using a pointer and you want to hold off its construction code until later, then you can.

Is this a good idea or a bad idea?

+4  A: 

I dislike it. It seems to me that after construction, an object should be... well... constructed. That code leaves it in an invalid state instead, which is almost1 never a good thing.

 

1 Weasel word inserted to account for unforeseen circumstances.

Michael Myers
A: 

Generally, source code should be as simple as possible, and your example is presented without the context, so it's just more complicated than necessary and therefore your example is a bad idea.

However, there may be some semantic contexts, where it may make sense to be able to deliver uninitialized objects - for instance, if the context requires a container to have objects but you don't want to initialize them until later because initialization is slow and/or maybe the objects are not needed. In those cases, the additional complexity may make something else simpler.

Lars D
+1  A: 

I believe constructor should basically do the init() part as well. Unless the object is fully constructed, it shouldn't be used.

Also, initializing in constructor allows you to make use of RAII. The basic point of RAII is to represent a resource by a local object, initialize in constructor, so that the local object's destructor will release the resource. That way, the programmer cannot forget to release the resource.

aJ
+3  A: 

Two-stage construction is generally considered a bad idea, if there are methods on the class which rely on the object being in some initialised state. Generally, I prefer constructors which guarantee the object is in a good state, or if that cannot be done (perhaps because some of the arguments to the constructor were invalid), throw an exception, so there is never an instances of your class which is in a bad state.

Requiring consumers of your object to remember to call init() is a bad idea, because they won't.

Dominic Rodger
+1  A: 

One case where this may apply is when 'Foo' is a attribute of another class and cannot be fully constructed before the parent-class is done. Only then can 'Foo' be 'filled-in'.

slashmais
A: 

The difference is that initialization happens after the call to the super class's constructor but before any code is executed in your local class constructor. Therefore, it really depends on your needs.

Andrew Sledge
In what language would that happen? If you construct an object using this method, any superclass constructor is run, the class constructor is run, then init() is called.
David Thornley
A: 

Although it cannot be considered a normal or preferred way of constructing objects, under some circumstances that maybe a way to go. For example you may need to construct an object just to indicate its existence (in some list, where count does matter etc.), but to init it later only if this particular object is used for the first time as initializing whole collection of objects would take to much time.

In that case it's good to expose the fact that object may be not initialized by including a method like isInitialized(). Also that way you can transfer initialization to another thread in order not to block the main thread of the application.

quosoo
+1  A: 

In some languages (read: C++) you can't call a constructor from another constructor, so if you want a common part of several constructors you need to put it in a separate method, and I've seen the name init() used for that. But that is not what you're talking about?

Thomas Padron-McCarthy
+1: Even in languages when you can call another constructor (read: Java) there may some constraints (like having to call it as a first thing in the other constructor body), which you may want to workaround. However in that case I would implement the init() method as private.
quosoo
+1  A: 

I use the contructor and init if I am instantiating objects that are based on a database call. So, if I need an empty object so that I can populate it and then save it to the database, I construct with no parameters and don't call init(). Whereas if I need to retrieve the object members from the db, I'll contruct($param) and pass the $param to init($param).

dnagirl
+3  A: 

In general, I agree that it's something to be avoided. But something none of the answers so far have addressed is the possibility that initialization may fail. Constructors cannot fail, so if your constructor allocates memory, or opens a file, or does anything else that may fail, you need a way to tell the caller that an error occurred. If you do the initialization in the constructor, then you need to have a flag that indicates whether or not the initialization succeeded, and then ensure that the caller checks that flag.

If you have a separate init() routine that must be called before anything else works, callers are more likely to check that return code than to call a didInitializationSucceed() method after creating the object.

Graeme Perrow
In C++, a constructor will throw an exception (the normal case) or return a 0 (if constructed with (nothrow)). It will not leave a partially constructed object.
David Thornley