Constructors build objects from dust.
Constructors are like "init functions". They turn a pile of arbitrary bits into a living object. Minimally they initialize internally used fields. They may also allocate resources (memory, files, semaphores, sockets, etc).
"ctor" is a typical abbreviation for constructor.
[ Top | Bottom | Previous section | Next section ]
A big difference!
Suppose that List is the name of some class. Then function f() declares a local List object called x:
But function g() declares a function called x() that returns a List:
[ Top | Bottom | Previous section | Next section ]
No way.
Dragons be here: if you call another constructor, the compiler initializes a temporary local object; it does not initialize this object. You can combine both constructors by using a default parameter, or you can share their common code in a private init() member function.
[ Top | Bottom | Previous section | Next section ]
No. A "default constructor" is a constructor that can be called with no arguments. Thus a constructor that takes no arguments is certainly a default constructor:
However it is possible (and even likely) that a default constructor can take arguments, provided they are given default values:
[ Top | Bottom | Previous section | Next section ]
Fred's default constructor (except as discussed below).
There is no way to tell the compiler to call a different constructor (except as discussed below). If your class Fred doesn't have a default constructor, attempting to create an array of Fred objects is trapped as an error at compile time.
However if you are constructing an object of the standard std::vector<Fred> rather than an array of Fred (which you probably should be doing anyway since arrays are evil), you don't have to have a default constructor in class Fred, since you can give the std::vector a Fred object to be used to initialize the elements:
Even though you ought to use a std::vector rather than an array, there are times when an array might be the right thing to do, and for those, there is the "explicit initialization of arrays" syntax. Here's how it looks:
Of course you don't have to do Fred(5,7) for every entry you can put in any numbers you want, even parameters or other variables. The point is that this syntax is (a) doable but (b) not as nice as the std::vector syntax. Remember this: arrays are evil unless there is a compelling reason to use an array, use a std::vector instead.
[ Top | Bottom | Previous section | Next section ]
Constructors should initialize all member objects in the initialization list.
For example, this constructor initializes member object x_ using an initialization list: Fred::Fred() : x_(whatever) { }. From a performance perspective, it is important to note that the whatever expression doesn't automatically cause a separate object to be created and copied into x_: if the types are the same the result of ...whatever... will be constructed directly inside x_.
In contrast the following constructor uses assignment: Fred::Fred() { x_ = whatever; }. In this case the expression whatever causes a separate, temporary object to be created, and this temporary object is passed into the x_ object's assignment operator, then is destructed at the ;. That's inefficient.
There's another source of inefficiency as well: in the second (assignment) case, the object's default constructor (implicitly called before the constructor body's "{") might, for example, allocate some default amount of memory or open some default file. All this work could be for naught if the whatever expression and/or assignment operator causes the object to close that file and/or release that memory (e.g., if the default constructor didn't allocate a large enough pool of memory or if it opened the wrong file).
Conclusion: All other things being equal, your code will run faster if you use initialization lists rather than assignment.
[ Top | Bottom | Previous section | Next section ]
Some people feel you should not use the this pointer in a constructor because the this object is not fully formed yet. However you can use this in the constructor (in the {body} and even in the initialization list) if you are careful.
Once you're in the {body} of the constructor, it's easy to imagine that you can use the this pointer since all the base class subobjects and the member objects will already have been fully constructed. However even there you must be careful. For example, if you call a virtual member function (or call some other function which turns around and calls a virtual member function) on the this object, you may not get what you want.
But you are even allowed to use the this pointer in the constructor's initializer list, provided you are very careful that you don't touch any member objects or base class subobjects that have not yet been constructed. This requires a rather intimate knowledge of the order that things happen in a constructor you have been warned. The safest thing to do is store the value of the this pointer somewhere and use that pointer later.
[ Top | Bottom | Previous section | Next section ]
A technique that provides more intuitive and/or safer construction operations for users of your class.
The problem is that constructors always have the same name as the class. Therefore the only way to differentiate between the various constructors of a class is by the parameter list. But if there are lots of constructors, the differences between the constructors becomes somewhat subtle and error prone.
With the Named Constructor Idiom, you declare all the class's constructors in the private: or protected: sections, and you provide public static methods that return an object. These static methods are the so-called "Named Constructors." In general there is one such static method for each different way to construct an object.
For example, suppose we are building a Point class that represents a position on the X-Y plane. Turns out there are two common ways to specify a 2-space coordinate: rectangular coordinates (X+Y), polar coordinates (Radius+Angle). (Don't worry if you can't remember these; the point isn't the particulars of coordinate systems; the point is that there are several ways to create a Point object). Unfortunately the parameters for these two coordinate systems are the same: two floats. This would create an ambiguity error in the overloaded constructors:
One way to solve this ambiguity is to use the Named Constructor Idiom:
Now the users of Point have a clear and unambiguous syntax for creating Points in either coordinate system:
Make sure your constructors are in the protected: section if you expect Point to have derived classes.
The Named Constructor Idiom can also be used to make sure your objects are always created via new.
[ Top | Bottom | Previous section | Next section ]
Because you must explicitly define your class's static data members.
Fred.h:
Fred.cpp (or Fred.C or whatever):
[ Top | Bottom | Previous section | Next section ]
Because static data members must be explicitly defined in exactly one compilation unit. If you didn't do this, you'll probably get an "undefined external" linker error. For example:
The linker will holler at you ("Fred::j_ is not defined") unless you define (as opposed to merely declare) Fred::j_ in (exactly) one of your source files:
The usual place to define static data members of class Fred is file Fred.cpp (or Fred.C or whatever source file extension you use).
[ Top | Bottom | Previous section | Next section ]
A subtle way to kill your project.
The static initialization order fiasco is a very subtle and commonly misunderstood aspect of C++. Unfortunately it's very hard to detect the errors occur before main() begins.
In short, suppose you have two static objects x and y which exist in separate source files, say x.cpp and y.cpp. Suppose further that the constructor for the y object calls some method on the x object.
That's it. It's that simple.
The tragedy is that you have a 50%-50% chance of dying. If the compilation unit for x.cpp happens to get initialized first, all is well. But if the compilation unit for y.cpp get initialized first, then y's constructor will get run before x's constructor, and you're toast. I.e., y's constructor will call a method on the x object, yet the x object hasn't yet been constructed.
I hear they're hiring down at McDonalds. Enjoy your new job flipping burgers.
If you think it's "exciting" to play Russian Roulette with live rounds in half the chambers, you can stop reading here. On the other hand if you like to improve your chances of survival by preventing disasters in a systematic way, you probably want to read the next FAQ.
Note: The static initialization order fiasco does not apply to builtin/intrinsic types like int or char*. For example if you create a static float object, there is never a problem with static initialization order. The only time the static initialization order is truly a fiasco is when your static or global objects have a constructor.
[ Top | Bottom | Previous section | Next section ]
Use the "construct on first use" idiom, which simply means to wrap your static object inside a function.
For example, suppose you have two classes, Fred and Barney. There is a global Fred object called x, and a global Barney object called y. Barney's constructor invokes the goBowling() method on the x object. The file x.cpp defines the x object:
The file y.cpp defines the y object:
For completeness the Barney constructor might look something like this:
As described above, the disaster occurs if y is constructed before x, which happens 50% of the time since they're in different source files.
There are many solutions to this problem, but a very simple and completely portable solution is to replace the global Fred object, x, with a global function, x(), that returns the Fred object by reference.
Since static local objects are constructed the first time control flows over their declaration (only), the above new Fred() statement will only happen once: the first time x() is called. Every subsequent call will return the same Fred object (the one pointed to by ans). Then all you do is change your usages of x to x():
This is called the Construct On First Use Idiom because it does just that: the global Fred object is constructed on its first use.
The downside of this approach is that the Fred object is never destructed. The C++ FAQ Book has a second technique that answers this concern (but at the cost of opening a "static de-initialization order fiasco").
Note: You don't have to do this for builtin/intrinsic types like int or char*. For example if you create a static or global float object, there is no need to wrap it within a function. The only time the static initialization order is truly a fiasco is when your static or global objects have a constructor.
[ Top | Bottom | Previous section | Next section ]
Just use the same technique just described, but this time use a static member function rather than a global function.
Suppose you have a class X that has a static Fred object:
Naturally this static member is initialized separately:
Naturally also the Fred object will be used in one or more of X's methods:
But now the "disaster scenario" is if someone somewhere somehow calls this method before the Fred object gets constructed. For example, if someone else creates a static X object and invokes its someMethod() method during static initialization, then you're at the mercy of the compiler as to whether the compiler will construct X::x_ before or after the someMethod() is called. (Note that the ANSI/ISO C++ committee is working on this problem, but compilers aren't yet generally available that handle these changes; watch this space for an update in the future.)
In any event, it's always portable and safe to change the X::x_ static data member into a static member function:
Naturally this static member is initialized separately:
Then you simply change any usages of x_ to x():
If you're super performance sensitive and you're concerned about the overhead of an extra function call on each invocation of X::someMethod() you can set up a static Fred& instead. As you recall, static local are only initialized once (the first time control flows over their declaration), so this will call X::x() only once: the first time X::someMethod() is called:
Note: You don't have to do this for builtin/intrinsic types like int or char*. For example if you create a static or global float object, there is no need to wrap it within a function. The only time the static initialization order is truly a fiasco is when your static or global objects have a constructor.
[ Top | Bottom | Previous section | Next section ]
Throw an exception. See [17.2] for details.
[ Top | Bottom | Previous section | Next section ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Jul 10, 2000