Archive-name: C++-faq/part3 Posting-Frequency: monthly Last-modified: Sep 8, 1997 URL: http://www.cerfnet.com/~mpcline/c++-faq-lite/ AUTHOR: Marshall Cline / cline@parashift.com COPYRIGHT: This posting is part of "C++ FAQ Lite." The entire "C++ FAQ Lite" document is Copyright(C) 1991-96 Marshall P. Cline, Ph.D., cline@parashift.com. All rights reserved. Copying is permitted only under designated situations. For details, see section [1]. NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS. THE AUTHOR PROVIDES NO WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, INCLUDING WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. C++-FAQ-Lite != C++-FAQ-Book: This document, C++ FAQ Lite, is not the same as the C++ FAQ Book. The book (C++ FAQs, Cline and Lomow, Addison-Wesley) is 500% larger than this document, and is available in bookstores. For details, see section [3]. ============================================================================== SECTION [7]: Classes and objects [7.1] What is a class? The fundamental building block of OO software. A class defines a data type, much like a struct would be in C. In a computer science sense, a type consists of both a set of states and a set of operations which transition between those states. Thus int is a type because it has both a set of states and it has operations like i + j or i++, etc. In exactly the same way, a class provides a set of (usually public:) operations, and a set of (usually non-public:) data bits representing the abstract values that instances of the type can have. Think of int as a class that has member functions called operator++, etc. Note: a C programmer can think of a class as a C struct whose members default to private. But if that's all you think of a class, then you probably need to experience a personal paradigm shift. ============================================================================== [7.2] What is an object? A region of storage with associated semantics. After the declaration int i; we say that "i is an object of type int." In OO/C++, "object" usually means "an instance of a class." Thus a class defines the behavior of possibly many objects (instances). ============================================================================== [7.3] When is an interface "good"? When it provides a simplified view of a chunk of software, and it is expressed in the vocabulary of a user (where a "chunk" is normally a class or a tight group of classes[14.2], and a "user" is another developer rather than the ultimate customer). * The "simplified view" means unnecessary details are intentionally hidden. This reduces the user's defect-rate. * The "vocabulary of users" means users don't need to learn a new set of words and concepts. This reduces the user's learning curve. ============================================================================== [7.4] What is encapsulation? Preventing unauthorized access to some piece of information or functionality. The key money-saving insight is to separate the volatile part of some chunk of software from the stable part. Encapsulation puts a firewall around the chunk, which prevents other chunks from accessing the volatile parts; other chunks can only access the stable parts. This prevents the other chunks from breaking if (when!) the volatile parts are changed. In context of OO software, a "chunk" is normally a class or a tight group of classes[14.2]. The "volatile parts" are the implementation details. If the chunk is a single class, the volatile part is normally encapsulated using the private: and/or protected: keywords[19.5]. If the chunk is a tight group of classes[14.2], encapsulation can be used to deny access to entire classes in that group. Inheritance[19] can also be used as a form of encapsulation[22.2]. The "stable parts" are the interfaces. A good interface provides a simplified view in the vocabulary of a user[7.3], and is designed from the outside-in[13.9] (here a "user" means another developer, not the end-user who buys the completed application). If the chunk is a single class, the interface is simply the class's public: member functions and friend[14] functions. If the chunk is a tight group of classes[14.2], the interface can include several of the classes in the chunk. Designing a clean interface and separating that interface from its implementation[22.1] merely allows users to use the interface. But encapsulating (putting "in a capsule") the implementation forces users to use the interface. ============================================================================== [7.5] How does C++ help with the tradeoff of safety vs. usability? In C, encapsulation[7.4] was accomplished by making things static in a compilation unit or module. This prevented another module from accessing the static stuff. (By the way, that use is now depreciated: don't do that in C++.) Unfortunately this approach doesn't support multiple instances of the data, since there is no direct support for making multiple instances of a module's static data. If multiple instances were needed in C, programmers typically used a struct. But unfortunately C structs don't support encapsulation[7.4]. This exacerbates the tradeoff between safety (information hiding) and usability (multiple instances). In C++, you can have both multiple instances and encapsulation via a class. The public: part of a class contains the class's interface, which normally consists of the class's public: member functions and its friend[14] functions. The private: and/or protected:[19.5] parts of a class contain the class's implementation, which is typically where the data lives. The end result is like an "encapsulated struct." This reduces the tradeoff between safety (information hiding) and usability (multiple instances). ============================================================================== [7.6] How can I prevent other programmers from violating encapsulation by seeing the private parts of my class? Not worth the effort -- encapsulation is for code, not people. It doesn't violate encapsulation for a programmer to see the private: and/or protected:[19.5] parts of your class, so long as they don't write code that somehow depends on what they saw. In other words, encapsulation doesn't prevent people from knowing about the inside of a class; it prevents the code they write from becoming dependent on the insides of the class. Your company doesn't have to pay a "maintenance cost" to maintain the gray matter between your ears; but it does have to pay a maintenance cost to maintain the code that comes out of your finger tips. What you know as a person doesn't increase maintenance cost, provided the code they write depends on the interface rather than the implementation. Besides, this is rarely if ever a problem. I don't know any programmers who have intentionally tried to accessed the private parts of a class. "My recommendation in such cases would be to change the programmer, not the code" [James Kanze, kanze@gabi-soft.fr; used with permission]. ============================================================================== [7.7] Is Encapsulation a Security device? No. Encapsulation != security. Encapsulation prevents mistakes, not espionage. ============================================================================== [7.8] What's the difference between the keywords struct and class? The members and base classes of a struct are public by default, while in class, they default to private. Note: you should make your base classes explicitly public, private, or protected, rather than relying on the defaults. struct and class are otherwise functionally equivalent. OK, enough of that squeaky clean techno talk. Emotionally, most developers make a strong distinction between a class and a struct. A struct simply feels like an open pile of bits with very little in the way of encapsulation or functionality. A class feels like a living and responsible member of society with intelligent services, a strong encapsulation barrier, and a well defined interface. Since that's the connotation most people already have, you should probably use the struct keyword if you have a class that has very few methods and has public data (such things do exist in well designed systems!), but otherwise you should probably use the class keyword. ============================================================================== SECTION [8]: References [8.1] What is a reference? An alias (an alternate name) for an object. References are frequently used for pass-by-reference: void swap(int& i, int& j) { int tmp = i; i = j; j = tmp; } main() { int x, y; // ... swap(x,y); } Here i and j are aliases for main's x and y respectively. In other words, i is x -- not a pointer to x, nor a copy of x, but x itself. Anything you do to i gets done to x, and vice versa. OK. That's how you should think of references as a programmer. Now, at the risk of confusing you by giving you a different perspective, here's how references are implemented. Underneath it all, a reference i to object x is typically the machine address of the object x. But when the programmer says i++, the compiler generates code that increments x. In particular, the address bits that the compiler uses to find x are not changed. A C programmer will think of this as if you used the C style pass-by-pointer, with the syntactic variant of (1) moving the & from the caller into the callee, and (2) eliminating the *s. In other words, a C programmer will think of i as a macro for (*p), where p is a pointer to x (e.g., the compiler automatically dereferences the underlying pointer; i++ is changed to (*p)++; i = 7 is automatically changed to *p = 7). Important note: Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object. It is not a pointer to the object, nor a copy of the object. It is the object. ============================================================================== [8.2] What happens if you assign to a reference? You change the referent (the object to which the reference refers). Remember: the reference is the referent, so changing the reference changes the referent. In compiler writer lingo, a reference is an "lvalue" (something that can appear on the left hand side of an assignment operator). ============================================================================== [8.3] What happens if you return a reference? The function call can appear on the left hand side of an assignment operator. This ability may seem strange at first. For example, no one thinks the expression f() = 7 makes sense. Yet, if a is an object of class Array, most people think that a[i] = 7 makes sense even though a[i] is really just a function call in disguise (it calls Array::operator[](int), which is the subscript operator for class Array). class Array { public: int size() const; float& operator[] (int index); // ... }; main() { Array a; for (int i = 0; i < a.size(); ++i) a[i] = 7; // This line invokes Array::operator[](int) } ============================================================================== [8.4] How can you reseat a reference to make it refer to a different object? No way. You can't separate the reference from the referent. Unlike a pointer, once a reference is bound to an object, it can not be "reseated" to another object. The reference itself isn't an object (it has no identity; taking the address of a reference gives you the address of the referent; remember: the reference is its referent). In that sense, a reference is similar to a const pointer[18.5] such as int* const p (as opposed to a pointer to const[18.4] such as const int* p). In spite of the gross similarity, please don't confuse references with pointers; they're not at all the same. ============================================================================== [8.5] When should I use references, and when should I use pointers? Use references when you can, and pointers when you have to. References are usually preferred over pointers whenever you don't need "reseating"[8.4]. This usually means that references are most useful in a class's public interface. References typically appear on the skin of an object, and pointers on the inside. The exception to the above is where a function's parameter or return value needs a "sentinel" reference. This is usually best done by returning/taking a pointer, and giving the NULL pointer this special significance (references should always alias objects, not a dereferenced NULL pointer). Note: Old line C programmers sometimes don't like references since they provide reference semantics that isn't explicit in the caller's code. After some C++ experience, however, one quickly realizes this is a form of information hiding, which is an asset rather than a liability. E.g., programmers should write code in the language of the problem rather than the language of the machine. ============================================================================== SECTION [9]: Inline functions [9.1] What's the deal with inline functions? An inline function is a function whose code gets inserted into the caller's code stream. Like a #define macro, inline functions improve performance by avoiding the overhead of the call itself and (especially!) by the compiler being able to optimize through the call ("procedural integration"). ============================================================================== [9.2] How can inline functions help with the tradeoff of safety vs. speed? In straight C, you can achieve "encapsulated structs" by putting a void* in a struct, in which case the void* points to the real data that is unknown to users of the struct. Therefore users of the struct don't know how to interpret the stuff pointed to by the void*, but the access functions cast the void* to the approprate hidden type. This gives a form of encapsulation. Unfortunately it forfeits type safety, and also imposes a function call to access even trivial fields of the struct (if you allowed direct access to the struct's fields, anyone and everyone would be able to get direct access since they would of necessity know how to interpret the stuff pointed to by the void*; this would make it difficult to change the underlying data structure). Function call overhead is small, but can add up. C++ classes allow function calls to be expanded inline. This lets you have the safety of encapsulation along with the speed of direct access. Furthermore the parameter types of these inline functions are checked by the compiler, an improvement over C's #define macros. ============================================================================== [9.3] Why should I use inline functions? Why not just use plain old #define macros? Because #define macros are evil. Unlike #define macros, inline functions avoid infamous macro errors since inline functions always evaluate every argument exactly once. In other words, invoking an inline function is semantically just like invoking a regular function, only faster: // A macro that returns the absolute value of i #define unsafe(i) \ ( (i) >= 0 ? (i) : -(i) ) // An inline function that returns the absolute value of i inline int safe(int i) { return i >= 0 ? i : -i; } int f(); void userCode(int x) { int ans; ans = unsafe(x++); // Error! x is incremented twice ans = unsafe(f()); // Danger! f() is called twice ans = safe(x++); // Correct! x is incremented once ans = safe(f()); // Correct! f() is called once } Also unlike macros, argument types are checked, and necessary conversions are performed correctly. Macros are bad for your health; don't use them unless you have to. ============================================================================== [9.4] How do you tell the compiler to make a non-member function inline? When you declare an inline function, it looks just like a normal function: void f(int i, char c); But when you define an inline function, you prepend the function's definition with the keyword inline, and you put the definition into a header file: inline void f(int i, char c) { // ... } Note: It's imperative that the function's definition (the part between the {...}) be placed in a header file, unless the function is used only in a single .cpp file. In particular, if you put the inline function's definition into a .cpp file and you call it from some other .cpp file, you'll get an "unresolved external" error from the linker. ============================================================================== [9.5] How do you tell the compiler to make a member function inline? When you declare an inline member function, it looks just like a normal member function: class Fred { public: void f(int i, char c); }; But when you define an inline member function, you prepend the member function's definition with the keyword inline, and you put the definition into a header file: inline void Fred::f(int i, char c) { // ... } It's usually imperative that the function's definition (the part between the {...}) be placed in a header file. If you put the inline function's definition into a .cpp file, and if it is called from some other .cpp file, you'll get an "unresolved external" error from the linker. ============================================================================== [9.6] Is there another way to tell the compiler to make a member function inline? Yep: define the member function in the class body itself: class Fred { public: void f(int i, char c) { // ... } }; Although this is easier on the person who writes the class, it's harder on all the readers since it mixes "what" a class does with "how" it does them. Because of this mixture, we normally prefer to define member functions outside the class body with the inline keyword[9.5]. The insight that makes sense of this: in a reuse-oriented world, there will usually be many people who use your class, but there is only one person who builds it (yourself); therefore you should do things that favor the many rather than the few. ============================================================================== [9.7] Are inline functions guaranteed to make your performance better? Nope. Beware that overuse of inline functions can cause code bloat, which can in turn have a negative performance impact in paging environments. ============================================================================== SECTION [10]: Constructors [10.1] What's the deal with constructors? 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. ============================================================================== [10.2] Is there any difference between List x; and List x();? A big difference! Suppose that List is the name of some class. Then function f() declares a local List object called x: void f() { List x; // Local object named x (of class List) // ... } But function g() declares a function called x() that returns a List: void g() { List x(); // Function named x (that returns a List) // ... } ============================================================================== [10.3] How can I make a constructor call another constructor as a primitive? 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. ============================================================================== [10.4] Is the default constructor for Fred always Fred::Fred()? 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: class Fred { public: Fred(); // Default constructor: can be called with no args // ... }; However it is possible (and even likely) that a default constructor can take arguments, provided they are given default values: class Fred { public: Fred(int i=3, int j=5); // Default constructor: can be called with no args // ... }; ============================================================================== [10.5] Which constructor gets called when I create an array of Fred objects? Fred's default constructor[10.4]. There is no way to tell the compiler to call a different constructor. If your class Fred doesn't have a default constructor[10.4], attempting to create an array of Fred objects is trapped as an error at compile time. class Fred { public: Fred(int i, int j); // ... assume there is no default constructor[10.4] in class Fred ... }; main() { Fred a[10]; // ERROR: Fred doesn't have a default constructor Fred* p = new Fred[10]; // ERROR: Fred doesn't have a default constructor } However if you are creating an STL[32.1] vector rather than an array of Fred (which you probably should be doing anyway since arrays are evil[21.5]), you don't have to have a default constructor in class Fred, since you can give the vector a Fred object to be used to initialize the elements: #include using namespace std; main() { vector a(10, Fred(5,7)); // The 10 Fred objects in vector a will be initialized with Fred(5,7). // ... } ============================================================================== [10.6] What is the "Named Constructor Idiom"? 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: class Point { public: Point(float x, float y); // Rectangular coordinates Point(float r, float a); // Polar coordinates (radius and angle) // ERROR: Overload is Ambiguous: Point::Point(float,float) }; main() { Point p = Point(5.7, 1.2); // Ambiguous: Which coordinate system? } One way to solve this ambiguity is to use the Named Constructor Idiom: #include // To get sin() and cos() class Point { public: static Point rectangular(float x, float y); // Rectangular coord's static Point polar(float radius, float angle); // Polar coordinates // These static methods are the so-called "named constructors" // ... private: Point(float x, float y); // Rectangular coordinates float x_, y_; }; inline Point::Point(float x, float y) : x_(x), y_(y) { } inline Point Point::rectangular(float x, float y) { return Point(x, y); } inline Point Point::polar(float radius, float angle) { return Point(radius*cos(angle), radius*sin(angle)); } Now the users of Point have a clear and unambiguous syntax for creating Points in either coordinate system: main() { Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular Point p2 = Point::polar(5.7, 1.2); // Obviously polar } Make sure your constructors are in the protected: section if you expect Fred to have derived classes. The Named Constructor Idiom can also be used to make sure your objects are always created via new[16.19]. ============================================================================== [10.7] Why can't I initialize my static member data in my constructor's initialization list? Because you must explicitly define your class's static data members. Fred.h: class Fred { public: Fred(); // ... private: int i_; static int j_; }; Fred.cpp (or Fred.C or whatever): Fred::Fred() : i_(10) // OK: you can (and should) initialize member data this way j_(42) // Error: you cannot initialize static member data like this { // ... } // You must define static data members this way: int Fred::j_ = 42; ============================================================================== [10.8] Why are classes with static data members getting linker errors? Because static data members must be explicitly defined in exactly one compilation unit[10.7]. If you didn't do this, you'll probably get an "undefined external" linker error. For example: // Fred.h class Fred { public: // ... private: static int j_; // Declares static data member Fred::j_ // ... }; 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: // Fred.cpp #include "Fred.h" int Fred::j_ = some_expression_evaluating_to_an_int; // Alternatively, if you wish to use the implicit 0 value for static ints: // int Fred::j_; 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). ============================================================================== [10.9] What's the "static initialization order fiasco"? [NEW!] [Recently created (on 9/97).] 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 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 reduce your chances of survival by preventing disasters in a systematic way, you probably want to read the next FAQ[10.10]. 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. ============================================================================== [10.10] How do I prevent the "static initialization order fiasco"? [NEW!] [Recently created (on 9/97).] 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: // File x.cpp #include "Fred.hpp" Fred x; The file y.cpp defines the y object: // File y.cpp #include "Barney.hpp" Barney y; For completeness the Barney constructor might look something like this: // File Barney.cpp #include "Barney.hpp" Barney::Barney() { // ... x.goBowling(); // ... } As described above[10.9], 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. // File x.cpp #include "Fred.hpp" Fred& x() { static Fred* ans = new Fred(); return *ans; } 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(): // File Barney.cpp #include "Barney.hpp" Barney::Barney() { // ... x().goBowling(); // ... } 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. ============================================================================== [10.11] How do I prevent the "static initialization order fiasco" for my static data members? [NEW!] [Recently created (on 9/97).] Just use the same technique just described[10.10], 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: // File X.hpp class X { public: // ... private: static Fred x_; }; Naturally this static member is initialized separately: // File X.cpp #include "X.hpp" Fred X::x_; Naturally also the Fred object will be used in one or more of X's methods: void X::someMethod() { x_.goBowling(); } 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: // File X.hpp class X { public: // ... private: static Fred& x(); }; Naturally this static member is initialized separately: // File X.cpp #include "X.hpp" Fred& X::x() { static Fred* ans = new Fred(); return *ans; } Then you simply change any usages of x_ to x(): void X::someMethod() { x().goBowling(); } 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: void X::someMethod() { static Fred& x = X::x(); x.goBowling(); } 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. ============================================================================== SECTION [11]: Destructors [11.1] What's the deal with destructors? A destructor gives an object its last rites. Destructors are used to release any resources allocated by the object. E.g., class Lock might lock a semaphore, and the destructor will release that semaphore. The most common example is when the constructor uses new, and the destructor uses delete. Destructors are a "prepare to die" member function. They are often abbreviated "dtor". ============================================================================== [11.2] What's the order that local objects are destructed? In reverse order of construction: First constructed, last destructed. In the following example, b's destructor will be executed first, then a's destructor: void userCode() { Fred a; Fred b; // ... } ============================================================================== [11.3] What's the order that objects in an array are destructed? In reverse order of construction: First constructed, last destructed. In the following example, the order for destructors will be a[9], a[8], ..., a[1], a[0]: void userCode() { Fred a[10]; // ... } ============================================================================== [11.4] Can I overload the destructor for my class? No. You can have only one destructor for a class Fred. It's always called Fred::~Fred(). It never takes any parameters, and it never returns anything. You can't pass parameters to the destructor anyway, since you never explicitly call a destructor[11.5] (well, almost never[11.10]). ============================================================================== [11.5] Should I explicitly call a destructor on a local variable? No! The destructor will get called again at the close } of the block in which the local was created. This is a guarantee of the language; it happens automagically; there's no way to stop it from happening. But you can get really bad results from calling a destructor on the same object a second time! Bang! You're dead! ============================================================================== [11.6] What if I want a local to "die" before the close } of the scope in which it was created? Can I call a destructor on a local if I really want to? No! [For context, please read the previous FAQ[11.5]]. Suppose the (desirable) side effect of destructing a local File object is to close the File. Now suppose you have an object f of a class File and you want File f to be closed before the end of the scope (i.e., the }) of the scope of object f: void someCode() { File f; // ... [This code that should execute when f is still open] ... // <-- We want the side-effect of f's destructor here! // ... [This code that should execute after f is closed] ... } There is a simple solution to this problem[11.7]. But in the mean time, remember: Do not explicitly call the destructor![11.5] ============================================================================== [11.7] OK, OK already; I won't explicitly call the destructor of a local; but how do I handle the above situation? [For context, please read the previous FAQ[11.6]]. Simply wrap the extent of the lifetime of the local in an artificial block { ... }: void someCode() { { File f; // ... [This code will execute when f is still open] ... } // ^-- f's destructor will automagically be called here! // ... [This code will execute after f is closed] ... } ============================================================================== [11.8] What if I can't wrap the local in an artificial block? Most of the time, you can limit the lifetime of a local by wrapping the local in an artificial block ({ ... })[11.7]. But if for some reason you can't do that, add a member function that has a similar effect as the destructor. But do not call the destructor itself! For example, in the case of class File, you might add a close() method. Typically the destructor will simply call this close() method. Note that the close() method will need to mark the File object so a subsequent call won't re-close an already-closed File. E.g., it might set the fileHandle_ data member to some nonsensical value such as -1, and it might check at the beginning to see if the fileHandle_ is already equal to -1: class File { public: void close(); ~File(); // ... private: int fileHandle_; // fileHandle_ >= 0 if/only-if it's open }; File::~File() { close(); } void File::close() { if (fileHandle_ >= 0) { // ... [Perform some operating-system call to close the file] ... fileHandle_ = -1; } } Note that the other File methods may also need to check if the fileHandle_ is -1 (i.e., check if the File is closed). ============================================================================== [11.9] But can I explicitly call a destructor if I've allocated my object with new? Probably not. Unless you used placement new[11.10], you should simply delete the object rather than explicitly calling the destructor. For example, suppose you allocated the object via a typical new expression: Fred* p = new Fred(); Then the destructor Fred::~Fred() will automagically get called when you delete it via: delete p; // Automagically calls p->~Fred() You should not explicitly call the destructor, since doing so won't release the memory that was allocated for the Fred object itself. Remember: delete p does two things[16.8]: it calls the destructor and it deallocates the memory. ============================================================================== [11.10] What is "placement new" and why would I use it? There are many uses of placement new. The simplest use is to place an object at a particular location in memory. This is done by supplying the place as a pointer parameter to the new part of a new expression: #include // Must #include this to use "placement new" #include "Fred.h" // Declaration of class Fred void someCode() { char memory[sizeof(Fred)]; // Line #1 void* place = memory; // Line #2 Fred* f = new(place) Fred(); // Line #3 (see "DANGER" below) // The pointers f and place will be equal // ... } Line #1 creates an array of sizeof(Fred) bytes of memory, which is big enough to hold a Fred object. Line #2 creates a pointer place that points to the first byte of this memory (experienced C programmers will note that this step was unnecessary; it's there only to make the code more obvious). Line #3 essentially just calls the constructor Fred::Fred(). The this pointer in the Fred constructor will be equal to place. The returned pointer f will therefore be equal to place. ADVICE: Don't use this "placement new" syntax unless you have to. Use it only when you really care that an object is placed at a particular location in memory. For example, when your hardware has a memory-mapped I/O timer device, and you want to place a Clock object at that memory location. DANGER: You are taking sole responsibility that the pointer you pass to the "placement new" operator points to a region of memory that is big enough and is properly aligned for the object type that you're creating. Neither the compiler nor the run-time system make any attempt to check whether you did this right. If your Fred class needs to be aligned on a 4 byte boundary but you supplied a location that isn't properly aligned, you can have a serious disaster on your hands (if you don't know what "alignment" means, please don't use the placement new syntax). You have been warned. You are also solely responsible for destructing the placed object. This is done by explicitly calling the destructor: void someCode() { char memory[sizeof(Fred)]; void* p = memory; Fred* f = new(p) Fred(); // ... f->~Fred(); // Explicitly call the destructor for the placed object } This is about the only time you ever explicitly call a destructor. ============================================================================== [11.11] When I write a destructor, do I need to explicitly call the destructors for my member objects? No. You never need to explicitly call a destructor (except with placement new[11.10]). A class's destructor (whether or not you explicitly define one) automagically invokes the destructors for member objects. They are destroyed in the reverse order they appear within the declaration for the class. class Member { public: ~Member(); // ... }; class Fred { public: ~Fred(); // ... private: Member x_; Member y_; Member z_; }; Fred::~Fred() { // Compiler automagically calls z_.~Member() // Compiler automagically calls y_.~Member() // Compiler automagically calls x_.~Member() } ============================================================================== [11.12] When I write a derived class's destructor, do I need to explicitly call the destructor for my base class? No. You never need to explicitly call a destructor (except with placement new[11.10]). A derived class's destructor (whether or not you explicitly define one) automagically invokes the destructors for base class subobjects. Base classes are destructed after member objects. In the event of multiple inheritance, direct base classes are destructed in the reverse order of their appearance in the inheritance list. class Member { public: ~Member(); // ... }; class Base { public: virtual ~Base(); // A virtual destructor[20.4] // ... }; class Derived : public Base { public: ~Derived(); // ... private: Member x_; }; Derived::~Derived() { // Compiler automagically calls x_.~Member() // Compiler automagically calls Base::~Base() } Note: Order dependencies with virtual inheritance are trickier. If you are relying on order dependencies in a virtual inheritance hierarchy, you'll need a lot more information than is in this FAQ. ============================================================================== SECTION [12]: Assignment operators [12.1] What is "self assignment"? Self assignment is when someone assigns an object with itself. For example, #include "Fred.hpp" // Declares class Fred void userCode(Fred& x) { x = x; // Self-assignment } Obviously no one ever explicitly does a self assignment like the above, but since more than one pointer or reference can point to the same object (aliasing), it is possible to have self assignment without knowning it: #include "Fred.hpp" // Declares class Fred void userCode(Fred& x, Fred& y) { x = y; // Could be self-assignment if &x == &y } main() { Fred z; userCode(z, z); } ============================================================================== [12.2] Why should I worry about "self assignment"? If you don't worry about self assignment[12.1], you'll expose your users to some very subtle bugs that have very subtle and often disastrous symptoms. For example, the following class will cause a complete disaster in the case of self-assignment: class Wilma { }; class Fred { public: Fred() : p_(new Wilma()) { } Fred(const Fred& f) : p_(new Wilma(*f.p_)) { } ~Fred() { delete p_; } Fred& operator= (const Fred& f) { // Bad code: Doesn't handle self-assignment! delete p_; // Line #1 p_ = new Wilma(*f.p_); // Line #2 return *this; } private: Wilma* p_; }; If someone assigns a Fred object with itself, line #1 deletes both this->p_ and f.p_ since *this and f are the same object. But line #2 uses *f.p_, which is no longer a valid object. This will likely cause a major disaster. The bottom line is that you the author of class Fred are responsible to make sure self-assignment on a Fred object is inocuous[12.3]. Do not assume that users won't ever do that to your objects. It is your fault if your object crashes when it gets a self-assignment. Aside: the above Fred::operator= (const Fred&) has a second problem: If an exception is thrown[17] while evaluating new Wilma(*f.p_) (e.g., an out-of-memory exception[16.5] or an exception in Wilma's copy constructor[17.1]), this->p_ will be a dangling pointer -- it will point to memory that is no longer valid. This can be solved by allocating the new objects before deleting the old objects. ============================================================================== [12.3] OK, OK, already; I'll handle self-assignment. How do I do it? You should worry about self assignment every time you create a class[12.2]. This does not mean that you need to add extra code to all your classes: as long as your objects gracefully handle self assignment, it doesn't matter whether you had to add extra code or not. If you do need to add extra code to your assignment operator, here's a simple and effective technique: Fred& Fred::operator= (const Fred& f) { if (this == &f) return *this; // Gracefully handle self assignment[12.1] // Put the normal assignment duties here... return *this; } This explicit test isn't always necessary. For example, if you were to fix the assignment operator in the previous FAQ[12.2] to handle exceptions thrown by new[16.5] and/or exceptions thrown by the copy constructor[17.1] of class Wilma, you might produce the following code. Note that this code has the (pleasant) side effect of automatically handling self assignment as well: Fred& operator= (const Fred& f) { // This code gracefully (albeit implicitly) handles self assignment[12.1] Wilma* tmp = new Wilma(*f.p_); // It would be OK if an exception[17] got thrown here delete p_; p_ = tmp; return *this; } Some programmers want to add "if (this == &f) return *this;" to make self assignment more efficient. This is generally the wrong tradeoff. If self assignment only occurs once in a thousand times, the if would waste cycles in 99.9% of the time (a test-and-branch can put a bubble in the pipeline of many superscalar processors). ==============================================================================