C Faqlite1
C Faqlite1
C Faqlite1
You can imagine that int is a class that has member functions called operator+
+, etc. (int isn't really a class, but the basic analogy is this: a class is a type,
much like int is a type.)
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.
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. If the chunk is a tight group of classes, encapsulation can be used to
deny access to entire classes in that group. Inheritance can also be used as a
form of encapsulation.
The "stable parts" are the interfaces. A good interface provides a simplified view
in the vocabulary of a user, and is designed from the outside-in (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 functions. If the chunk is a tight group of classes, the
interface can include several of the classes in the chunk.
Designing a clean interface and separating that interface from its implementation
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?
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. 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 functions. The private
and/or protected 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).
Besides, this is rarely if ever a problem. I don't know any programmers who have
intentionally tried to access the private parts of a class. "My recommendation in
such cases would be to change the programmer, not the code" [James Kanze;
used with permission].
No.
Encapsulation != security.
[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.
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.
8] References
(Part of C++ FAQ Lite, Copyright © 1991-2006, Marshall Cline,
[email protected])
int 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).
You change the state of the referent (the referent is the object to which the
reference refers).
Remember: the reference is the referent, so changing the reference changes the
state of the referent. In compiler writer lingo, a reference is an "lvalue"
(something that can appear on the left hand side of an assignment operator).
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);
...
};
int main()
{
Array a;
for (int i = 0; i < a.size(); ++i)
a[i] = 7; // This line invokes Array::operator[](int)
...
}
It chains these method calls, which is why this is called method chaining.
The first thing that gets executed is object.method1(). This returns some object,
which might be a reference to object (i.e., method1() might end with return
*this;), or it might be some other object. Let's call the returned object objectB.
Then objectB becomes the this object of method2().
The most common use of method chaining is in the iostream library. E.g., cout
<< x << y works because cout << x is a function that returns cout.
A less common, but still rather slick, use for method chaining is in the Named
Parameter Idiom.
No way.
In that sense, a reference is similar to a const pointer such as int* const p (as
opposed to a pointer to const 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.
Use references when you can, and pointers when you have to.
References are usually preferred over pointers whenever you don't need
"reseating". 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 — a reference that does not refer to an object. 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.
The term handle is used to mean any technique that lets you get to another
object — a generalized pseudo-pointer. The term is (intentionally) ambiguous
and vague.
Ambiguity is actually an asset in certain cases. For example, during early design
you might not be ready to commit to a specific representation for the handles.
You might not be sure whether you'll want simple pointers vs. references vs.
pointers-to-pointers vs. references-to-pointers vs. integer indices into an array
vs. strings (or other key) that can be looked up in a hash-table (or other data
structure) vs. database keys vs. some other technique. If you merely know that
you'll need some sort of thingy that will uniquely identify and get to an object, you
call the thingy a Handle.
Novices often think in terms of pointers, but in reality there are downside risks to
using raw pointers. E.g., what if the Fred object needs to move? How do we
know when it's safe to delete the Fred objects? What if the Fred object needs to
(temporarily) get serialized on disk? etc., etc. Most of the time we add more
layers of indirection to manage situations like these. For example, the handles
might be Fred**, where the pointed-to Fred* pointers are guaranteed to never
move but when the Fred objects need to move, you just update the pointed-to
Fred* pointers. Or you make the handle an integer then have the Fred objects (or
pointers to the Fred objects) looked up in a table/array/whatever. Or whatever.
The point is that we use the word Handle when we don't yet know the details of
what we're going to do.
Another time we use the word Handle is when we want to be vague about what
we've already done (sometimes the term magic cookie is used for this as well, as
in, "The software passes around a magic cookie that is used to uniquely identify
and locate the appropriate Fred object"). The reason we (sometimes) want to be
vague about what we've already done is to minimize the ripple effect if/when the
specific details/representation of the handle change. E.g., if/when someone
changes the handle from a string that is used in a lookup table to an integer that
is looked up in an array, we don't want to go and update a zillion lines of code.
When the compiler inline-expands a function call, the function's code gets
inserted into the caller's code stream (conceptually similar to what happens with
a #define macro). This can, depending on a zillion other things, improve
performance, because the optimizer can procedurally integrate the called code
— optimize the called code into the caller.
There are several ways to designate that a function is inline, some of which
involve the inline keyword, others do not. No matter how you designate a
function as inline, it is a request that the compiler is allowed to ignore: it might
inline-expand some, all, or none of the calls to an inline function. (Don't get
discouraged if that seems hopelessly vague. The flexibility of the above is
actually a huge advantage: it lets the compiler treat large functions differently
from small ones, plus it lets the compiler generate code that is easy to debug if
you select the right compiler options.)
void f()
{
int x = /*...*/;
int y = /*...*/;
int z = /*...*/;
...code that uses x, y and z...
g(x, y, z);
...more code that uses x, y and z...
}
Assuming a typical C++ implementation that has registers and a stack, the
registers and parameters get written to the stack just before the call to g(), then
the parameters get read from the stack inside g() and read again to restore the
registers while g() returns to f(). But that's a lot of unnecessary reading and
writing, especially in cases when the compiler is able to use registers for
variables x, y and z: each variable could get written twice (as a register and also
as a parameter) and read twice (when used within g() and to restore the
registers during the return to f()).
If the compiler inline-expands the call to g(), all those memory operations could
vanish. The registers wouldn't need to get written or read since there wouldn't be
a function call, and the parameters wouldn't need to get written or read since the
optimizer would know they're already in registers.
Naturally your mileage may vary, and there are a zillion variables that are outside
the scope of this particular FAQ, but the above serves as an example of the sorts
of things that can happen with procedural integration.
There are no simple answers. inline functions might make the code faster, they
might make it slower. They might make the executable larger, they might make it
smaller. They might cause thrashing, they might prevent thrashing. And they
might be, and often are, totally irrelevant to speed.
inline functions might make it slower: Too much inlining might cause code
bloat, which might cause "thrashing" on demand-paged virtual-memory systems.
In other words, if the executable size is too big, the system might spend most of
its time going out to disk to fetch the next chunk of code.
inline functions might make it larger: This is the notion of code bloat, as
described above. For example, if a system has 100 inline functions each of
which expands to 100 bytes of executable code and is called in 100 places, that's
an increase of 1MB. Is that 1MB going to cause problems? Who knows, but it is
possible that that last 1MB could cause the system to "thrash," and that could
slow things down.
inline functions might make it smaller: The compiler often generates more
code to push/pop registers/parameters than it would by inline-expanding the
function's body. This happens with very small functions, and it also happens with
large functions when the optimizer is able to remove a lot of redundant code
through procedural integration — that is, when the optimizer is able to make the
large function small.
inline functions might cause thrashing: Inlining might increase the size of the
binary executable, and that might cause thrashing.
inline functions might prevent thrashing: The working set size (number of
pages that need to be in memory at once) might go down even if the executable
size goes up. When f() calls g(), the code is often on two distinct pages; when
the compiler procedurally integrates the code of g() into f(), the code is often on
the same page.
inline functions might increase the number of cache misses: Inlining might
cause an inner loop to span across multiple lines of the memory cache, and that
might cause thrashing of the memory-cache.
inline functions might be irrelevant to speed: Most systems are not CPU-
bound. Most systems are I/O-bound, database-bound or network-bound,
meaning the bottleneck in the system's overall performance is the file system, the
database or the network. Unless your "CPU meter" is pegged at 100%, inline
functions probably won't make your system faster. (Even in CPU-bound systems,
inline will help only when used within the bottleneck itself, and the bottleneck is
typically in only a small percentage of the code.)
There are no simple answers: You have to play with it to see what is best. Do
not settle for simplistic answers like, "Never use inline functions" or "Always use
inline functions" or "Use inline functions if and only if the function is less than
N lines of code." These one-size-fits-all rules may be easy to write down, but they
will produce sub-optimal results.
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.5] Why should I use inline functions instead of plain old #define
macros?
Because #define macros are evil in 4 different ways: evil#1, evil#2, evil#3, and
evil#4. Sometimes you should use them anyway, but they're still 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:
int f();
void userCode(int x)
{
int ans;
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.
When you declare an inline function, it looks just like a normal function:
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.
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.
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. 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. This approach is further exploited in the next FAQ.
class Foo {
public:
void method(); ← best practice: don't put the inline keyword here
...
};
inline void Foo::method() ← best practice: put the inline keyword here
{ ... }
• The public: part of the class body is where you describe the observable
semantics of a class, its public member functions, its friend functions, and
anything else exported by the class. Try not to provide any inklings of
anything that can't be observed from the caller's code.
• The other parts of the class, including non- public: part of the class body,
the definitions of your member and friend functions, etc. are pure
implementation. Try not to describe any observable semantics that were
not already described in the class's public: part.
From a practical standpoint, this separation makes life easier and safer for your
users. Say Chuck wants to simply "use" your class. Because you read this FAQ
and used the above separation, Chuck can read your class's public: part and
see everything he needs to see and nothing he doesn't need to see. His life is
easier because he needs to look in only one spot, and his life is safer because
his pure mind isn't polluted by implementation minutiae.
NOTE: most people use the terms "declaration" and "definition" to differentiate
the above two places. For example, they might say, "Should I put the inline
keyword next to the declaration or the definition?" Unfortunately that usage is
sloppy and somebody out there will eventually gig you for it. The people who gig
you are probably insecure, pathetic wannabes who know they're not good
enough to actually acomplish something with their lives, nonetheless you might
as well learn the correct terminology to avoid getting gigged. Here it is: every
definition is also a declaration. This means using the two as if they are mutually
exclusive would be like asking which is heavier, steel or metal? Almost
everybody will know what you mean if you use "definition" as if it is the opposite
of "declaration," and only the worst of the techie weenies will gig you for it, but at
least you now know how to use the terms correctly.
[10] Constructors
(Part of C++ FAQ Lite, Copyright © 1991-2006, Marshall Cline,
[email protected])
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).
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)
...
}
class Foo {
public:
Foo(char x);
Foo(char x, int y);
...
};
Foo::Foo(char x)
{
...
Foo(x, 0); // this line does NOT help initialize the this object!!
...
}
class Foo {
public:
Foo(char x, int y=0); // this line combines the two constructors
...
};
If that doesn't work, e.g., if there isn't an appropriate default parameter that
combines the two constructors, sometimes you can share their common code in
a private init() member function:
class Foo {
public:
Foo(char x);
Foo(char x, int y);
...
private:
void init(char x, int y);
};
Foo::Foo(char x)
{
init(x, int(x) + 7);
...
}
Foo::Foo(char x, int y)
{
init(x, y);
...
}
BTW do NOT try to achieve this via placement new. Some people think they can
say new(this) Foo(x, int(x)+7) within the body of Foo::Foo(char). However
that is bad, bad, bad. Please don't write me and tell me that it seems to work on
your particular version of your particular compiler; it's bad. Constructors do a
bunch of little magical things behind the scenes, but that bad technique steps on
those partially constructed bits. Just say no.
class Fred {
public:
Fred(); // Default constructor: can be called with no args
...
};
class Fred {
public:
Fred(int i=3, int j=5); // Default constructor: can be called with no args
...
};
class Fred {
public:
Fred();
...
};
int main()
{
Fred a[10]; ← calls the default constructor 10 times
Fred* p = new Fred[10]; ← calls the default constructor 10 times
...
}
If your class doesn't have a default constructor, you'll get a compile-time error
when you attempt to create an array using the above simple syntax:
class Fred {
public:
Fred(int i, int j); ← assume there is no default constructor
...
};
int 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, even if your class already has a default constructor, you should try to
use std::vector<Fred> rather than an array (arrays are evil). std::vector lets
you decide to use any constructor, not just the default constructor:
#include <vector>
int main()
{
std::vector<Fred> a(10, Fred(5,7)); ← the 10 Fred objects in std::vect
or a will be initialized with Fred(5,7)
...
}
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, you might need
the "explicit initialization of arrays" syntax. Here's how:
class Fred {
public:
Fred(int i, int j); ← assume there is no default constructor
...
};
int main()
{
Fred a[10] = {
Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), // The 10 Fre
d objects are
Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7) // initialized us
ing Fred(5,7)
};
...
}
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.
Finally, you can use placement-new to manually initialize the elements of the
array. Warning: it's ugly: the raw array can't be of type Fred, so you'll need a
bunch of pointer-casts to do things like compute array index operations. Warning:
it's compiler- and hardware-dependent: you'll need to make sure the storage is
aligned with an alignment that is at least as strict as is required for objects of
class Fred. Warning: it's tedious to make it exception-safe: you'll need to
manually destruct the elements, including in the case when an exception is
thrown part-way through the loop that calls the constructors. But if you really
want to do it anyway, read up on placement-new. (BTW placement-new is the
magic that is used inside of std::vector. The complexity of getting everything
right is yet another reason to use std::vector.)
By the way, did I ever mention that arrays are evil? Or did I mention that you
ought to use a std::vector unless there is a compelling reason to use an array?
The other (inefficient) way to build constructors is via assignment, such as:
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 that temporary object is
destructed at the ;. That's inefficient.
As if that wasn't bad enough, there's another source of inefficiency when using
assignment in a constructor: the member object will get fully constructed by its
default constructor, and this 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.
Now for the exceptions. Every rule has exceptions (hmmm; does "every rule has
exceptions" have exceptions? reminds me of Gödel's Incompleteness
Theorems), and there are a couple of exceptions to the "use initialization lists"
rule. Bottom line is to use common sense: if it's cheaper, better, faster, etc. to not
use them, then by all means, don't use them. This might happen when your class
has two constructors that need to initialize the this object's data members in
different orders. Or it might happen when two data members are self-referential.
Or when a data-member needs a reference to the this object, and you want to
avoid a compiler warning about using the this keyword prior to the { that begins
the constructor's body (when your particular compiler happens to issue that
particular warning). Or when you need to do an if/throw test on a variable
(parameter, global, etc.) prior to using that variable to initialize one of your this
members. This list is not exhaustive; please don't write me asking me to add
another "Or when...". The point is simply this: use common sense.
Some people feel you should not use the this pointer in a constructor because
the 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.
Here is something that always works: the {body} of a constructor (or a function
called from the constructor) can reliably access the data members declared in a
base class and/or the data members declared in the constructor's own class.
This is because all those data members are guaranteed to have been fully
constructed by the time the constructor's {body} starts executing.
Here is something that never works: the {body} of a constructor (or a function
called from the constructor) cannot get down to a derived class by calling a
virtual member function that is overridden in the derived class. If your goal was
to get to the overridden function in the derived class, you won't get what you
want. Note that you won't get to the override in the derived class independent of
how you call the virtual member function: explicitly using the this pointer (e.g.,
this->method()), implicitly using the this pointer (e.g., method()), or even calling
some other function that calls the virtual member function on your this object.
The bottom line is this: even if the caller is constructing an object of a derived
class, during the constructor of the base class, your object is not yet of that
derived class. You have been warned.
Here is something that sometimes works: if you pass any of the data members in
this object to another data member's initializer, you must make sure that the
other data member has already been initialized. The good news is that you can
determine whether the other data member has (or has not) been initialized using
some straightforward language rules that are independent of the particular
compiler you're using. The bad news it that you have to know those language
rules (e.g., base class sub-objects are initialized first (look up the order if you
have multiple and/or virtual inheritance!), then data members defined in the
class are initialized in the order in which they appear in the class declaration). If
you don't know these rules, then don't pass any data member from the this
object (regardless of whether or not you explicitly use the this keyword) to any
other data member's initializer! And if you do know the rules, please be careful.
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 them become 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)
};
int 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:
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_;
};
Now the users of Point have a clear and unambiguous syntax for creating Points
in either coordinate system:
int 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 Point to
have derived classes.
The Named Constructor Idiom can also be used to make sure your objects are
always created via new.
Note that the Named Constructor Idiom, at least as implemented above, is just as
fast as directly calling a constructor — modern compilers will not make any extra
copies of your object.
Not necessarily.
To keep the example clean, let's strip things down to the bare essentials.
Suppose yourCode() calls rbv() ("rbv" stands for "return by value") which returns
a Foo object by value:
Foo rbv();
void yourCode()
{
Foo x = rbv(); ← the return-value of rbv() goes into x
...
}
Now the question is, How many Foo objects will there be? Will rbv() create a
temporary Foo object that gets copy-constructed into x? How many temporaries?
Said another way, does return-by-value necessarily degrade performance?
The point of this FAQ is that the answer is No, commercial-grade C++ compilers
implement return-by-value in a way that lets them eliminate the overhead, at
least in simple cases like those shown in the previous FAQ. In particular, all(?)
commercial-grade C++ compilers will optimize this case:
Foo rbv()
{
...
return Foo(42, 73); ← suppose Foo has a ctor Foo::Foo(int a, int b)
}
Certainly the compiler is allowed to create a temporary, local Foo object, then
copy-construct that temporary into variable x within yourCode(), then destruct the
temporary. But all(?) commercial-grade C++ compilers won't do that: the return
statement will directly construct x itself. Not a copy of x, not a pointer to x, not a
reference to x, but x itself.
You can stop here if you don't want to genuinely understand the previous
paragraph, but if you want to know the secret sauce (so you can, for example,
reliably predict when the compiler can and cannot provide that optimization for
you), the key is to know that compilers usually implement return-by-value using
pass-by-pointer. When yourCode() calls rbv(), the compiler secretly passes a
pointer to the location where rbv() is supposed to construct the "returned"
object. It might look something like this (it's shown as a void* rather than a Foo*
since the Foo object has not yet been constructed):
// Pseudo-code
void rbv(void* put_result_here) ← Original C++ code: Foo rbv()
{
...
}
// Pseudo-code
void yourCode()
{
struct Foo x;
rbv(&x); ← Original C++ code: Foo x = rbv()
...
}
So the first ingredient in the secret sauce is that the compiler (usually) transforms
return-by-value into pass-by-pointer. This means that commercial-grade
compilers don't bother creating a temporary: they directly construct the returned
object in the location pointed to by put_result_here.
The second ingredient in the secret sauce is that compilers typically implement
constructors using a similar technique. This is compiler-dependent and
somewhat idealized (I'm intentionally ignoring how to handle new and
overloading), but compilers typically implement Foo::Foo(int a, int b) using
something like this:
// Pseudo-code
void Foo_ctor(Foo* this, int a, int b) ← Original C++ code: Foo::Foo(int
a, int b)
{
...
}
Putting these together, the compiler might implement the return statement in
rbv() by simply passing put_result_here as the constructor's this pointer:
// Pseudo-code
void rbv(void* put_result_here) ← Original C++ code: Foo rbv()
{
...
Foo_ctor((Foo*)put_result_here, 42, 73); ← Original C++ code: return Fo
o(42,73);
return;
}
So yourCode() passes &x to rbv(), and rbv() in turn passes &x to the constructor
(as the this pointer). That means constructor directly constructs x.
In the early 90s I did a seminar for IBM's compiler group in Toronto, and one of
their engineers told me that they found this return-by-value optimization to be so
fast that you get it even if you don't compile with optimization turned on. Because
the return-by-value optimization causes the compiler to generate less code, it
actually improves compile-times in addition to making your generated code
smaller and faster. The point is that the return-by-value optimization is almost
universally implemented, at least in code cases like those shown above.
The compiler might construct ans in a local object, then in the return statement
copy-construct ans into the location pointed to by put_result_here and destruct
ans. But if all return statements return the same local object, in this case ans, the
compiler is also allowed to construct ans in the location pointed to by
put_result_here:
// Pseudo-code
void rbv(void* put_result_here) ← Original C++ code: Foo rbv()
{
...
Foo_ctor((Foo*)put_result_here, 42, 73); ← Original C++ code: Foo ans =
Foo(42,73);
...
do_something_with(*(Foo*)put_result_here); ← Original C++ code: do_some
thing_with(ans);
...
return; ← Original C++ code: return ans;
}
Final thought: this discussion was limited to whether there will be any extra
copies of the returned object in a return-by-value call. Don't confuse that with
other things that could happen in yourCode(). For example, if you changed
yourCode() from Foo x = rbv(); to Foo x; x = rbv(); (note the ; after the
declaration), the compiler is required to use Foo's assignment operator, and
unless the compiler can prove that Foo's default constructor followed by
assignment operator is exactly the same as its copy constructor, the compiler is
required by the language to put the returned object into an unnamed temporary
within yourCode(), use the assignment operator to copy the temporary into x,
then destruct the temporary. The return-by-value optimization still plays its part
since there will be only one temporary, but by changing Foo x = rbv(); to Foo
x; x = rbv();, you have prevented the compiler from eliminating that last
temporary.
Because you must explicitly define your class's static data members.
Fred.h:
class Fred {
public:
Fred();
...
private:
int i_;
static int j_;
};
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
{
...
}
[10.11] Why are classes with static data members getting linker
errors?
// 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"
// 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).
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 initialization for the y
object (typically the y object's constructor) calls some method on the x object.
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 initialization will get run before x's initialization,
and you're toast. E.g., y's constructor could 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 can also, in some cases, apply to built-
in/intrinsic types.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
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.h"
Fred x;
// File y.cpp
#include "Barney.h"
Barney y;
For completeness the Barney constructor might look something like this:
// File Barney.cpp
#include "Barney.h"
Barney::Barney()
{
...
x.goBowling();
...
}
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.h"
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.h"
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. There
is another technique that answers this concern, but it needs to be used with care
since it creates the possibility of another (equally nasty) problem.
Note: The static initialization order fiasco can also, in some cases, apply to built-
in/intrinsic types.
Short answer: it's possible to use a static object rather than a static pointer, but
doing so opens up another (equally subtle, equally nasty) problem.
Long answer: sometimes people worry about the fact that the previous solution
"leaks." In many cases, this is not a problem, but it is a problem in some cases.
Note: even though the object pointed to by ans in the previous FAQ is never
deleted, the memory doesn't actually "leak" when the program exits since the
operating system automatically reclaims all the memory in a program's heap
when that program exits. In other words, the only time you'd need to worry about
this is when the destructor for the Fred object performs some important action
(such as writing something to a file) that must occur sometime while the program
is exiting.
In those cases where the construct-on-first-use object (the Fred, in this case)
needs to eventually get destructed, you might consider changing function x() as
follows:
// File x.cpp
#include "Fred.h"
Fred& x()
{
static Fred ans; // was static Fred* ans = new Fred();
return ans; // was return *ans;
}
However there is (or rather, may be) a rather subtle problem with this change. To
understand this potential problem, let's remember why we're doing all this in the
first place: we need to make 100% sure our static object (a) gets constructed
prior to its first use and (b) doesn't get destructed until after its last use.
Obviously it would be a disaster if any static object got used either before
construction or after destruction. The message here is that you need to worry
about two situations (static initialization and static deinitialization), not just one.
By changing the declaration from static Fred* ans = new Fred(); to static
Fred ans;, we still correctly handle the initialization situation but we no longer
handle the deinitialization situation. For example, if there are 3 static objects, say
a, b and c, that use ans during their destructors, the only way to avoid a static
deinitialization disaster is if ans is destructed after all three.
The point is simple: if there are any other static objects whose destructors might
use ans after ans is destructed, bang, you're dead. If the constructors of a, b and
c use ans, you should normally be okay since the runtime system will, during
static deinitialization, destruct ans after the last of those three objects is
destructed. However if a and/or b and/or c fail to use ans in their constructors
and/or if any code anywhere gets the address of ans and hands it to some other
static object, all bets are off and you have to be very, very careful.
There is a third approach that handles both the static initialization and static
deinitialization situations, but it has other non-trivial costs. I'm too lazy (and
busy!) to write any more FAQs today so if you're interested in that third approach,
you'll have to buy a book that describes that third approach in detail. The C++
FAQs book is one of those books, and it also gives the cost/benefit analysis to
decide if/when that third approach should be used.
Just use the same technique just described, but this time use a static member
function rather than a global function.
// File X.h
class X {
public:
...
private:
static Fred x_;
};
// File X.cpp
#include "X.h"
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.h
class X {
public:
...
private:
static Fred& x();
};
// File X.cpp
#include "X.h"
Fred& X::x()
{
static Fred* ans = new Fred();
return *ans;
}
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: The static initialization order fiasco can also, in some cases, apply to built-
in/intrinsic types.
Yes.
If you initialize your built-in/intrinsic type using a function call, the static
initialization order fiasco is able to kill you just as bad as with user-defined/class
types. For example, the following code shows the failure:
#include <iostream>
int x = f();
int y = g();
int f()
{
std::cout << "using 'y' (which is " << y << ")\n";
return 3*y + 7;
}
int g()
{
std::cout << "initializing 'y'\n";
return 5;
}
The output of this little program will show that it uses y before initializing it. The
solution, as before, is the Construct On First Use Idiom:
#include <iostream>
int& x()
{
static int ans = f();
return ans;
}
int& y()
{
static int ans = g();
return ans;
}
int f()
{
std::cout << "using 'y' (which is " << y() << ")\n";
return 3*y() + 7;
}
int g()
{
std::cout << "initializing 'y'\n";
return 5;
}
Of course you might be able to simplify this by moving the initialization code for x
and y into their respective functions:
#include <iostream>
int& x()
{
static int ans;
return ans;
}
int& y()
{
static int ans;
return ans;
}
And, if you can get rid of the print statements you can further simplify these to
something really simple:
int& x()
{
static int ans = 3*y() + 7;
return ans;
}
int& y()
{
static int ans = 5;
return ans;
}
Furthermore, since y is initialized using a constant expression, it no longer needs
its wrapper function — it can be a simple variable again.
The fundamental problem solved by the Named Parameter Idiom is that C++ only
supports positional parameters. For example, a caller of a function isn't allowed
to say, "Here's the value for formal parameter xyz, and this other thing is the
value for formal parameter pqr." All you can do in C++ (and C and Java) is say,
"Here's the first parameter, here's the second parameter, etc." The alternative,
called named parameters and implemented in the language Ada, is especially
useful if a function takes a large number of mostly default-able parameters.
Over the years people have cooked up lots of workarounds for the lack of named
parameters in C and C++. One of these involves burying the parameter values in
a string parameter then parsing this string at run-time. This is what's done in the
second parameter of fopen(), for example. Another workaround is to combine all
the boolean parameters in a bit-map, then the caller or's a bunch of bit-shifted
constants together to produce the actual parameter. This is what's done in the
second parameter of open(), for example. These approaches work, but the
following technique produces caller-code that's more obvious, easier to write,
easier to read, and is generally more elegant.
The idea, called the Named Parameter Idiom, is to change the function's
parameters to methods of a newly created class, where all these methods return
*this by reference. Then you simply rename the main function into a
parameterless "do-it" method on that class.
The example will be for the "open a file" concept. Let's say that concept logically
requires a parameter for the file's name, and optionally allows parameters for
whether the file should be opened read-only vs. read-write vs. write-only, whether
or not the file should be created if it doesn't already exist, whether the writing
location should be at the end ("append") or the beginning ("overwrite"), the block-
size if the file is to be created, whether the I/O is buffered or non-buffered, the
buffer-size, whether it is to be shared vs. exclusive access, and probably a few
others. If we implemented this concept using a normal function with positional
parameters, the caller code would be very difficult to read: there'd be as many as
8 positional parameters, and the caller would probably make a lot of mistakes. So
instead we use the Named Parameter Idiom.
Before we go through the implementation, here's what the caller code might look
like, assuming you are willing to accept all the function's default parameters:
File f = OpenFile("foo.txt");
That's the easy case. Now here's what it might look like if you want to change a
bunch of the parameters.
File f = OpenFile("foo.txt")
.readonly()
.createIfNotExist()
.appendWhenWriting()
.blockSize(1024)
.unbuffered()
.exclusiveAccess();
Notice how the "parameters", if it's fair to call them that, are in random order
(they're not positional) and they all have names. So the programmer doesn't
have to remember the order of the parameters, and the names are (hopefully)
obvious.
So here's how to implement it: first we create a class ( OpenFile) that houses all
the parameter values as private data members. The required parameters (in this
case, the only required parameter is the file's name) is implemented as a normal,
positional parameter on OpenFile's constructor, but that constructor doesn't
actually open the file. Then all the optional parameters (readonly vs. readwrite,
etc.) become methods. These methods (e.g., readonly(), blockSize(unsigned),
etc.) return a reference to their this object so the method calls can be chained.
class File;
class OpenFile {
public:
OpenFile(const std::string& filename);
// sets all the default values for each data member
OpenFile& readonly(); // changes readonly_ to true
OpenFile& readwrite(); // changes readonly_ to false
OpenFile& createIfNotExist();
OpenFile& blockSize(unsigned nbytes);
...
private:
friend class File;
std::string filename_;
bool readonly_; // defaults to false [for example]
bool createIfNotExist_; // defaults to false [for example]
...
unsigned blockSize_; // defaults to 4096 [for example]
...
};
The only other thing to do is make the constructor for class File to take an
OpenFile object:
class File {
public:
File(const OpenFile& params);
...
};
This constructor gets the actual parameters from the OpenFile object, then
actually opens the file:
Note that OpenFile declares File as its friend, that way OpenFile doesn't need a
bunch of (otherwise useless) public: get methods.
Since each member function in the chain returns a reference, there is no copying
of objects and the chain is highly efficient. Furthermore, if the various member
functions are inline, the generated object code will probably be on par with C-
style code that sets various members of a struct. Of course if the member
functions are not inline, there may be a slight increase in code size and a slight
decrease in performance (but only if the construction occurs on the critical path
of a CPU-bound program; this is a can of worms I'll try to avoid opening; read the
C++ FAQs book for a rather thorough discussion of the issues), so it may, in this
case, be a tradeoff for making the code more reliable.
[10.19] Why am I getting an error after declaring a Foo object via Foo
x(Bar())?
Because that doesn't create a Foo object - it declares a non-member function that
returns a Foo object.
First, here's a better explanation of the problem. Suppose there is a class called
Bar that has a default ctor. This might even be a library class such as
std::string, but for now we'll just call it Bar:
class Bar {
public:
Bar();
...
};
Now suppose there's another class called Foo that has a ctor that takes a Bar. As
before, this might be defined by someone other than you.
class Foo {
public:
Foo(const Bar& b); // or perhaps Foo(Bar b)
...
void blah();
...
};
Now you want to create a Foo object using a temporary Bar. In other words, you
want to create an object via Bar(), and pass that to the Foo ctor to create a local
Foo object called x:
void yourCode()
{
Foo x(Bar()); ← you think this creates a Foo object called x...
x.blah(); ← ...but it doesn't, so this line gives you a bizarre error message
...
}
It's a long story, but the solution (hope you're sitting down!) is to use = in your
declaration:
void yourCode()
{
Foo x = Foo(Bar()); ← Yes, Virginia, that thar syntax really works
x.blah(); ← Ahhhh, this works now — no more error messages
...
}
Here's why that happens (this part is optional; only read it if you think your future
as a programmer is worth two minutes of your precious time today): When the
compiler sees Foo x(Bar()), it thinks that the Bar() part is declaring a non-
member function that returns a Bar object, so it thinks you are declaring the
existence of a function called x that returns a Foo and that takes as a single
parameter of type "non-member function that takes nothing and returns a Bar."
Now here's the sad part. In fact it's pathetic. Some mindless drone out there is
going to skip that last paragraph, then they're going to impose a bizarre,
incorrect, irrelevant, and just plain stupid coding standard that says something
like, "Never create temporaries using a default constructor" or "Always use = in
all initializations" or something else equally inane. If that's you, please fire
yourself before you do any more damage. Those who don't understand the
problem shouldn't tell others how to solve it. Harumph.
(Okay, that was mostly tongue in cheek. But there's a grain of truth in it. The real
problem is that people tend to worship consistency, and they tend to extrapolate
from the obscure to the common. That's not wise.)
[11] Destructors
(Part of C++ FAQ Lite, Copyright © 1991-2006, Marshall Cline,
[email protected])
FAQs in section [11]:
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".
In the following example, b's destructor will be executed first, then a's destructor:
void userCode()
{
Fred a;
Fred b;
...
}
In the following example, the order for destructors will be a[9], a[8], ..., a[1],
a[0]:
void userCode()
{
Fred a[10];
...
}
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 (well, almost never).
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!
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[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?
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;
There is a simple solution to this problem. But in the mean time, remember: Do
not explicitly call the destructor!
Simply wrap the extent of the lifetime of the local in an artificial block {...}:
void someCode()
{
{
File f;
...insert code that should execute when f is still open...
}← f's destructor will automagically be called here!
Most of the time, you can limit the lifetime of a local by wrapping the local in an
artificial block ({...}). 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) {
...insert code to call the OS 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).
Note also that any constructors that don't actually open a file should set
fileHandle_ to -1.
Unless you used placement new, you should simply delete the object rather than
explicitly calling the destructor. For example, suppose you allocated the object
via a typical new expression:
Then the destructor Fred::~Fred() will automagically get called when you delete
it via:
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: it calls the destructor and it deallocates the memory.
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:
void someCode()
{
char memory[sizeof(Fred)]; // Line #1
void* place = memory; // Line #2
...
}
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.
Note: there is a much cleaner but more sophisticated way of handling the
destruction / deletion situation.
No. You never need to explicitly call a destructor (except with placement new).
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()
}
No. You never need to explicitly call a destructor (except with placement new).
class Member {
public:
~Member();
...
};
class Base {
public:
virtual ~Base(); // A virtual destructor
...
};
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.
Yes. The good news is that these "memory pools" are useful in a number of
situations. The bad news is that I'll have to drag you through the mire of how it
works before we discuss all the uses. But if you don't know about memory pools,
it might be worthwhile to slog through this FAQ — you might learn something
useful!
Okay, assuming you've used placement new and have survived the above two
lines of code, the next step is to turn your memory allocator into an object. This
kind of object is called a "memory pool" or a "memory arena." This lets your
users have more than one "pool" or "arena" from which memory will be allocated.
Each of these memory pool objects will allocate a big chunk of memory using
some specific system call (e.g., shared memory, persistent memory, stack
memory, etc.; see below), and will dole it out in little chunks as needed. Your
memory-pool class might look something like this:
class Pool {
public:
void* alloc(size_t nbytes);
void dealloc(void* p);
private:
...data members used in your pool object...
};
void Pool::dealloc(void* p)
{
...your algorithm goes here...
}
Now one of your users might have a Pool called pool, from which they could
allocate objects like this:
Pool pool;
...
void* raw = pool.alloc(sizeof(Foo));
Foo* p = new(raw) Foo();
Or simply:
The reason it's good to turn Pool into a class is because it lets users create N
different pools of memory rather than having one massive pool shared by all
users. That allows users to do lots of funky things. For example, if they have a
chunk of the system that allocates memory like crazy then goes away, they could
allocate all their memory from a Pool, then not even bother doing any deletes on
the little pieces: just deallocate the entire pool at once. Or they could set up a
"shared memory" area (where the operating system specifically provides memory
that is shared between multiple processes) and have the pool dole out chunks of
shared memory rather than process-local memory. Another angle: many systems
support a non-standard function often called alloca() which allocates a block of
memory from the stack rather than the heap. Naturally this block of memory
automatically goes away when the function returns, eliminating the need for
explicit deletes. Someone could use alloca() to give the Pool its big chunk of
memory, then all the little pieces allocated from that Pool act like they're local:
they automatically vanish when the function returns. Of course the destructors
don't get called in some of these cases, and if the destructors do something
nontrivial you won't be able to use these techniques, but in cases where the
destructor merely deallocates memory, these sorts of techniques can be useful.
Okay, assuming you survived the 6 or 8 lines of code needed to wrap your
allocate function as a method of a Pool class, the next step is to change the
syntax for allocating objects. The goal is to change from the rather clunky syntax
new(pool.alloc(sizeof(Foo))) Foo() to the simpler syntax new(pool) Foo(). To
make this happen, you need to add the following two lines of code just below the
definition of your Pool class:
Now when the compiler sees new(pool) Foo(), it calls the above operator new
and passes sizeof(Foo) and pool as parameters, and the only function that ends
up using the funky pool.alloc(nbytes) method is your own operator new.
Now to the issue of how to destruct/deallocate the Foo objects. Recall that the
brute force approach sometimes used with placement new is to explicitly call the
destructor then explicitly deallocate the memory:
Problem #1: plugging the memory leak. When you use the "normal" new
operator, e.g., Foo* p = new Foo(), the compiler generates some special code to
handle the case when the constructor throws an exception. The actual code
generated by the compiler is functionally similar to this:
The point is that the compiler deallocates the memory if the ctor throws an
exception. But in the case of the "new with parameter" syntax (commonly called
"placement new"), the compiler won't know what to do if the exception occurs so
by default it does nothing:
So the goal is to force the compiler to do something similar to what it does with
the global new operator. Fortunately it's simple: when the compiler sees
new(pool) Foo(), it looks for a corresponding operator delete. If it finds one, it
does the equivalent of wrapping the ctor call in a try block as shown above. So
we would simply provide an operator delete with the following signature (be
careful to get this right; if the second parameter has a different type from the
second parameter of the operator new(size_t, Pool&), the compiler doesn't
complain; it simply bypasses the try block when your users say new(pool)
Foo()):
After this, the compiler will automatically wrap the ctor calls of your new
expressions in a try block:
// This is functionally what happens with Foo* p = new(pool) Foo()
Foo* p;
The idea is to implicitly associate a Pool* with every allocation. The Pool*
associated with the global allocator would be NULL, but at least conceptually you
could say every allocation has an associated Pool*. Then you replace the global
operator delete so it looks up the associated Pool*, and if non-NULL, calls that
Pool's deallocate function. For example, if(!) the normal deallocator used free(),
the replacment for the global operator delete would look something like this:
If you're not sure if the normal deallocator was free(), the easiest approach is
also replace the global operator new with something that uses malloc(). The
replacement for the global operator new would look something like this (note:
this definition ignores a few details such as the new_handler loop and the throw
std::bad_alloc() that happens if we run out of memory):
Even though this technique requires a std::map look-up for each deallocation, it
seems to have acceptable performance, at least in many cases.
Another approach that is faster but might use more memory and is a little trickier
is to prepend a Pool* just before all allocations. For example, if nbytes was 24,
meaning the caller was asking to allocate 24 bytes, we would allocate 28 (or 32 if
you think the machine requires 8-byte alignment for things like doubles and/or
long longs), stuff the Pool* into the first 4 bytes, and return the pointer 4 (or 8)
bytes from the beginning of what you allocated. Then your global operator
delete backs off the 4 (or 8) bytes, finds the Pool*, and if NULL, uses free()
otherwise calls pool->dealloc(). The parameter passed to free() and pool-
>dealloc() would be the pointer 4 (or 8) bytes to the left of the original
parameter, p. If(!) you decide on 4 byte alignment, your code would look
something like this (although as before, the following operator new code elides
the usual out-of-memory handlers):
Naturally the last few paragraphs of this FAQ are viable only when you are
allowed to change the global operator new and operator delete. If you are not
allowed to change these global functions, the first three quarters of this FAQ is
still applicable.
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 knowing it:
int main()
{
Fred z;
userCode(z, z);
...
}
If you don't worry about self assignment, 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 to 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 innocuous. 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 while evaluating new Wilma(*f.p_) (e.g., an out-of-memory exception or an
exception in Wilma's copy constructor), 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.
You should worry about self assignment every time you create a class. 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:
return *this;
}
This explicit test isn't always necessary. For example, if you were to fix the
assignment operator in the previous FAQ to handle exceptions thrown by new
and/or exceptions thrown by the copy constructor 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:
In cases like the previous example (where self assignment is harmless but
inefficient), some programmers want to improve the efficiency of self assignment
by adding an otherwise unnecessary test, such as "if (this == &f) return
*this;". It is generally the wrong tradeoff to make self assignment more efficient
by making the non-self assignment case less efficient. For example, adding the
above if test to the Fred assignment operator would make the non-self
assignment case slightly less efficient (an extra (and unnecessary) conditional
branch). If self assignment actually occured once in a thousand times, the if
would waste cycles 99.9% of the time.
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 knowing it:
int main()
{
Fred z;
userCode(z, z);
...
}
If you don't worry about self assignment, 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 to 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 innocuous. 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 while evaluating new Wilma(*f.p_) (e.g., an out-of-memory exception or an
exception in Wilma's copy constructor), 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.
You should worry about self assignment every time you create a class. 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:
return *this;
}
This explicit test isn't always necessary. For example, if you were to fix the
assignment operator in the previous FAQ to handle exceptions thrown by new
and/or exceptions thrown by the copy constructor 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:
In cases like the previous example (where self assignment is harmless but
inefficient), some programmers want to improve the efficiency of self assignment
by adding an otherwise unnecessary test, such as "if (this == &f) return
*this;". It is generally the wrong tradeoff to make self assignment more efficient
by making the non-self assignment case less efficient. For example, adding the
above if test to the Fred assignment operator would make the non-self
assignment case slightly less efficient (an extra (and unnecessary) conditional
branch). If self assignment actually occured once in a thousand times, the if
would waste cycles 99.9% of the time.
[14] Friends
(Part of C++ FAQ Lite, Copyright © 1991-2006, Marshall Cline,
[email protected])
Friends can be either functions or other classes. A class grants access privileges
to its friends. Normally a developer has political and technical control over both
the friend and member functions of a class (else you may need to get
permission from the owner of the other pieces when you want to update your
own class).
You often need to split a class in half when the two halves will have different
numbers of instances or different lifetimes. In these cases, the two halves usually
need direct access to each other (the two halves used to be in the same class,
so you haven't increased the amount of code that needs direct access to a data
structure; you've simply reshuffled the code into two classes instead of one). The
safest way to implement this is to make the two halves friends of each other.
If you use friends like just described, you'll keep private things private. People
who don't understand this often make naive efforts to avoid using friendship in
situations like the above, and often they actually destroy encapsulation. They
either use public data (grotesque!), or they make the data accessible between
the halves via public get() and set() member functions. Having a public get()
and set() member function for a private datum is OK only when the private
datum "makes sense" from outside the class (from a user's perspective). In many
cases, these get()/set() member functions are almost as bad as public data:
they hide (only) the name of the private datum, but they don't hide the existence
of the private datum.
(Many people think of a friend function as something outside the class. Instead,
try thinking of a friend function as part of the class's public interface. A friend
function in the class declaration doesn't violate encapsulation any more than a
public member function violates encapsulation: both have exactly the same
authority with respect to accessing the class's non-public parts.)
Member functions and friend functions are equally privileged (100% vested).
The major difference is that a friend function is called like f(x), while a member
function is called like x.f(). Thus the ability to choose between member
functions (x.f()) and friend functions (f(x)) allows a designer to select the
syntax that is deemed most readable, which lowers maintenance costs.
The major disadvantage of friend functions is that they require an extra line of
code when you want dynamic binding. To get the effect of a virtual friend, the
friend function should call a hidden (usually protected) virtual member
function. This is called the Virtual Friend Function Idiom. For example:
class Base {
public:
friend void f(Base& b);
...
protected:
virtual void do_f();
...
};
void userCode(Base& b)
{
f(b);
}
Use a member when you can, and a friend when you have to.
Sometimes friends are syntactically better (e.g., in class Fred, friend functions
allow the Fred parameter to be second, while members require it to be first).
Another good use of friend functions are the binary infix arithmetic operators.
E.g., aComplex + aComplex should be defined as a friend rather than a member if
you want to allow aFloat + aComplex as well (member functions don't allow
promotion of the left hand argument, since that would change the class of the
object that is the recipient of the member function invocation).
Increase type safety, reduce errors, allow extensibility, and provide inheritability.
printf() is arguably not broken, and scanf() is perhaps livable despite being
error prone, however both are limited with respect to what C++ I/O can do. C++
I/O (using << and >>) is, relative to C (using printf() and scanf()):
• More type-safe: With <iostream>, the type of object being I/O'd is known
statically by the compiler. In contrast, <cstdio> uses "%" fields to figure
out the types dynamically.
• Less error prone: With <iostream>, there are no redundant "%" tokens that
have to be consistent with the actual objects being I/O'd. Removing
redundancy removes a class of errors.
• Extensible: The C++ <iostream> mechanism allows new user-defined
types to be I/O'd without breaking existing code. Imagine the chaos if
everyone was simultaneously adding new incompatible "%" fields to
printf() and scanf()?!
• Inheritable: The C++ <iostream> mechanism is built from real classes
such as std::ostream and std::istream. Unlike <cstdio>'s FILE*, these
are real classes and hence inheritable. This means you can have other
user-defined things that look and act like streams, yet that do whatever
strange and wonderful things you want. You automatically get to use the
zillions of lines of I/O code written by users you don't even know, and they
don't need to know about your "extended stream" class.
For example, suppose you have the following code that reads integers from
std::cin:
#include <iostream>
int main()
{
std::cout << "Enter numbers separated by whitespace (use -1 to quit):
";
int i = 0;
while (i != -1) {
std::cin >> i; // BAD FORM — See comments below
std::cout << "You entered " << i << '\n';
}
...
}
The problem with this code is that it lacks any checking to see if someone
entered an invalid input character. In particular, if someone enters something that
doesn't look like an integer (such as an 'x'), the stream std::cin goes into a
"failed state," and all subsequent input attempts return immediately without doing
anything. In other words, the program enters an infinite loop; if 42 was the last
number that was successfully read, the program will print the message You
entered 42 over and over.
An easy way to check for invalid input is to move the input request from the body
of the while loop into the control-expression of the while loop. E.g.,
#include <iostream>
int main()
{
std::cout << "Enter a number, or -1 to quit: ";
int i = 0;
while (std::cin >> i) { // GOOD FORM
if (i == -1) break;
std::cout << "You entered " << i << '\n';
}
...
}
This will cause the while loop to exit either when you hit end-of-file, or when you
enter a bad integer, or when you enter -1.
(Naturally you can eliminate the break by changing the while loop expression
from while (std::cin >> i) to while ((std::cin >> i) && (i != -1)), but
that's not really the point of this FAQ since this FAQ has to do with iostreams
rather than generic structured programming guidelines.)
#include <iostream>
#include <limits>
int main()
{
int age = 0;
std::cout << "You are " << age << " years old\n";
...
}
Of course you can also print the error message when the input is out of range.
For example, if you wanted the age to be between 1 and 200, you could change
the while loop to:
...
while ((std::cout << "How old are you? ")
&& (!(std::cin >> age) || age < 1 || age > 200)) {
std::cout << "That's not a number between 1 and 200; ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
...
[15.4] How does that funky while (std::cin >> foo) syntax work?
See the previous FAQ for an example of the "funky while (std::cin >> foo)
syntax."
The expression (std::cin >> foo) calls the appropriate operator>> (for
example, it calls the operator>> that takes an std::istream on the left and, if foo
is of type int, an int& on the right). The std::istream operator>> functions
return their left argument by convention, which in this case means it will return
std::cin. Next the compiler notices that the returned std::istream is in a
boolean context, so it converts that std::istream into a boolean.
The operator void*() cast operator returns some non-NULL pointer if the stream
is in a good state, or NULL if it's in a failed state. For example, if you read one too
many times (e.g., if you're already at end-of-file), or if the actual info on the input
stream isn't valid for the type of foo (e.g., if foo is an int and the data is an 'x'
character), the stream will go into a failed state and the cast operator will return
NULL.
The reason operator>> doesn't simply return a bool (or void*) indicating whether
it succeeded or failed is to support the "cascading" syntax:
[15.5] Why does my input seem to process past the end of file?
Because the eof state may not get set until after a read is attempted past the end
of file. That is, reading the last byte from a file might not set the eof state. E.g.,
suppose the input stream is mapped to a keyboard — in that case it's not even
theoretically possible for the C++ library to predict whether or not the character
that the user just typed will be the last character.
For example, the following code might have an off-by-one error with the count i:
int i = 0;
while (! std::cin.eof()) { // WRONG! (not reliable)
std::cin >> x;
++i;
// Work with x ...
}
int i = 0;
while (std::cin >> x) { // RIGHT! (reliable)
++i;
// Work with x ...
}
Because the numerical extractor leaves non-digits behind in the input buffer.
char name[1000];
int age;
for (;;) {
std::cout << "Name: ";
std::cin >> name;
std::cout << "Age: ";
std::cin >> age;
}
for (;;) {
std::cout << "Name: ";
std::cin >> name;
std::cout << "Age: ";
std::cin >> age;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Of course you might want to change the for (;;) statement to while
(std::cin), but don't confuse that with skipping the non-numeric characters at
the end of the loop via the line: std::cin.ignore(...);.
Using std::endl flushes the output buffer after sending a '\n', which means
std::endl is more expensive in performance. Obviously if you need to flush the
buffer after sending a '\n', then use std::endl; but if you don't need to flush the
buffer, the code will run faster if you use '\n'.
void g()
{
std::cout << ...stuff... << std::endl;
}
void h()
{
std::cout << ...stuff... << std::flush;
}
#include <iostream>
class Fred {
public:
friend std::ostream& operator<< (std::ostream& o, const Fred& fred);
...
private:
int i_; // Just for illustration
};
int main()
{
Fred f;
std::cout << "My Fred object: " << f << "\n";
...
}
We use a non-member function (a friend in this case) since the Fred object is
the right-hand operand of the << operator. If the Fred object was supposed to be
on the left hand side of the << (that is, myFred << std::cout rather than
std::cout << myFred), we could have used a member function named
operator<<.
Note that operator<< returns the stream. This is so the output operations can be
cascaded.
No.
The usual reason people want to always use a printOn() method rather than a
friend function is because they wrongly believe that friends violate
encapsulation and/or that friends are evil. These beliefs are naive and wrong:
when used properly, friends can actually enhance encapsulation.
This is not to say that the printOn() method approach is never useful. For
example, it is useful when providing printing for an entire hierarchy of classes.
But if you use a printOn() method, it should normally be protected, not public.
For completeness, here is "the printOn() method approach." The idea is to have
a member function, often called printOn(), that does the actual printing, then
have operator<< call that printOn() method. When it is done wrongly, the
printOn() method is public so operator<< doesn't have to be a friend — it can
be a simple top-level function that is neither a friend nor a member of the class.
Here's some sample code:
#include <iostream>
class Fred {
public:
void printOn(std::ostream& o) const;
...
};
// The actual printing is done inside the printOn() method [NOT recommended!]
void Fred::printOn(std::ostream& o) const
{
...
}
People wrongly assume that this reduces maintenance cost "since it avoids
having a friend function." This is a wrong assumption because:
#include <iostream>
class Fred {
public:
friend std::istream& operator>> (std::istream& i, Fred& fred);
...
private:
int i_; // Just for illustration
};
int main()
{
Fred f;
std::cout << "Enter a Fred object: ";
std::cin >> f;
...
}
Note that operator>> returns the stream. This is so the input operations can be
cascaded and/or used in a while loop or if statement.
class Base {
public:
friend std::ostream& operator<< (std::ostream& o, const Base& b);
...
protected:
virtual void printOn(std::ostream& o) const;
};
inline std::ostream& operator<< (std::ostream& o, const Base& b)
{
b.printOn(o);
return o;
}
The end result is that operator<< acts as if it were dynamically bound, even
though it's a friend function. This is called the Virtual Friend Function Idiom.
Use std::ios::binary.
Some operating systems differentiate between text and binary modes. In text
mode, end-of-line sequences and possibly other things are translated; in binary
mode, they are not. For example, in text mode under Windows, "\r\n" is
translated into "\n" on input, and the reverse on output.
#include <string>
#include <iostream>
#include <fstream>
Note: input >> c discards leading whitespace, so you won't normally use that
when reading binary files.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
For example, suppose you want to do binary I/O using std::cin and std::cout.
You should use forward slashes in your filenames, even on operating systems
that use backslashes (DOS, Windows, OS/2, etc.). For example:
#include <iostream>
#include <fstream>
int main()
{
#if 1
std::ifstream file("../test.dat"); // RIGHT!
#else
std::ifstream file("..\test.dat"); // WRONG!
#endif
...
}
[15.17] How can I tell {if a key, which key} was pressed before the
user presses the ENTER key?
This is not a standard C++ feature — C++ doesn't even require your system to
have a keyboard!. That means every operating system and vendor does it
somewhat differently.
Please read the documentation that came with your compiler for details on your
particular installation.
(By the way, the process on UNIX typically has two steps: first set the terminal to
single-character mode, then use either select() or poll() to test if a key was
pressed. You might be able to adapt this code.)
This is not a standard C++ feature — C++ doesn't even require your system to
have a keyboard or a screen. That means every operating system and vendor
does it somewhat differently.
Please read the documentation that came with your compiler for details on your
particular installation.
This is not a standard C++ feature — C++ doesn't even require your system to
have a screen. That means every operating system and vendor does it
somewhat differently.
Please read the documentation that came with your compiler for details on your
particular installation.
This is not a standard C++ feature — C++ doesn't even require your system to
have a screen. That means every operating system and vendor does it
somewhat differently.
Please read the documentation that came with your compiler for details on your
particular installation.
This is not a standard C++ feature — C++ doesn't even require your system to
have a screen. That means every operating system and vendor does it
somewhat differently.
Please read the documentation that came with your compiler for details on your
particular installation.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
The pointed-to-data.
No! (Assuming you didn't get that pointer back from new in between.)
void yourCode()
{
Foo* p = new Foo();
delete p;
delete p; ← disaster!
...
}
That second delete p line might do some really bad things to you. It might,
depending on the phase of the moon, corrupt your heap, crash your program,
make arbitrary and bizarre changes to objects that are already out there on the
heap, etc. Unfortunately these symptoms can appear and disappear randomly.
According to Murphy's law, you'll be hit the hardest at the worst possible moment
(when the customer is looking, when a high-value transaction is trying to post,
etc.).
Note: some runtime systems will protect you from certain very simple cases of
double delete. Depending on the details, you might be okay if you happen to be
running on one of those systems and if no one ever deploys your code on
another system that handles things differently and if you are deleting something
that doesn't have a destructor and if you don't do anything significant between
the two deletes and if no one ever changes your code to do something
significant between the two deletes and if your thread scheduler (over which you
likely have no control!) doesn't happen to swap threads between the two deletes
and if, and if, and if. So back to Murphy: since it can go wrong, it will, and it will
go wrong at the worst possible moment.
Do NOT email me saying you tested it and it doesn't crash. Get a clue. A non-
crash don't prove the absence of a bug; it merely fails to prove the presence of a
bug.
[16.3] Can I free() pointers allocated with new? Can I delete pointers
allocated with malloc()?
No!
It is perfectly legal, moral, and wholesome to use malloc() and delete in the
same program, or to use new and free() in the same program. But it is illegal,
immoral, and despicable to call free() with a pointer allocated via new, or to call
delete on a pointer allocated via malloc().
Beware! I occasionally get e-mail from people telling me that it works OK for
them on machine X and compiler Y. Just because they don't see bad symptoms
in a simple test case doesn't mean it won't crash in the field. Even if they know it
won't crash on their particular compiler doesn't mean it will work safely on
another compiler, another platform, or even another version of the same
compiler.
Beware! Sometimes people say, "But I'm just working with an array of char."
Nonetheless do not mix malloc() and delete on the same pointer, or new and
free() on the same pointer! If you allocated via p = new char[n], you must use
delete[] p; you must not use free(p). Or if you allocated via p = malloc(n),
you must use free(p); you must not use delete[] p or delete p! Mixing these
up could cause a catastrophic failure at runtime if the code was ported to a new
machine, a new compiler, or even a new version of the same compiler.
No!
When realloc() has to copy the allocation, it uses a bitwise copy operation,
which will tear many C++ objects to shreds. C++ objects should be allowed to
copy themselves. They use their own copy constructor or assignment operator.
Besides all that, the heap that new uses may not be the same as the heap that
malloc() and realloc() use!
No! (But if you have an old compiler, you may have to force the new operator to
throw an exception if it runs out of memory.)
It turns out to be a real pain to always write explicit NULL tests after every new
allocation. Code like the following is very tedious:
Fred* p = new Fred();
if (p == NULL)
throw std::bad_alloc();
If your compiler doesn't support (or if you refuse to use) exceptions, your code
might be even more tedious:
Take heart. In C++, if the runtime system cannot allocate sizeof(Fred) bytes of
memory during p = new Fred(), a std::bad_alloc exception will be thrown.
Unlike malloc(), new never returns NULL!
However, if your compiler is old, it may not yet support this. Find out by checking
your compiler's documentation under "new". If you have an old compiler, you may
have to force the compiler to have this behavior.
Note: If you are using Microsoft Visual C++, to get new to throw an exception
when it fails you must #include some standard header in at least one of your .cpp
files. For example, you could #include <new> (or <iostream> or <string> or ...).
If you have an old compiler that doesn't automagically perform the NULL test, you
can force the runtime system to do the test by installing a "new handler" function.
Your "new handler" function can do anything you want, such as throw an
exception, delete some objects and return (in which case operator new will retry
the allocation), print a message and abort() the program, etc.
Here's a sample "new handler" that prints a message and throws an exception.
The handler is installed using std::set_new_handler():
#include <new> // To get std::set_new_handler
#include <cstdlib> // To get abort()
#include <iostream> // To get std::cerr
void myNewHandler()
{
// This is your own handler. It can do anything you want.
throw alloc_error();
}
int main()
{
std::set_new_handler(myNewHandler); // Install your "new handler"
...
}
After the std::set_new_handler() line is executed, operator new will call your
myNewHandler() if/when it runs out of memory. This means that new will never
return NULL:
Note: If your compiler doesn't support exception handling, you can, as a last
resort, change the line throw ...; to:
Note: If some global/static object's constructor uses new, it won't use the
myNewHandler() function since that constructor will get called before main()
begins. Unfortunately there's no convenient way to guarantee that the
std::set_new_handler() will be called before the first use of new. For example,
even if you put the std::set_new_handler() call in the constructor of a global
object, you still don't know if the module ("compilation unit") that contains that
global object will be elaborated first or last or somewhere inbetween. Therefore
you still don't have any guarantee that your call of std::set_new_handler() will
happen before any other global's constructor gets invoked.
No!
The C++ language guarantees that delete p will do nothing if p is equal to NULL.
Since you might get the test backwards, and since most testing methodologies
force you to explicitly test every branch point, you should not put in the redundant
if test.
Wrong:
if (p != NULL)
delete p;
Right:
delete p;
[16.9] What are the two steps that happen when I say delete p?
delete p is a two-step process: it calls the destructor, then releases the memory.
The code generated for delete p is functionally similar to this (assuming p is of
type Fred*):
The statement p->~Fred() calls the destructor for the Fred object pointed to by p.
The statement operator delete(p) calls the memory deallocation primitive, void
operator delete(void* p). This primitive is similar in spirit to free(void* p).
(Note, however, that these two are not interchangeable; e.g., there is no
guarantee that the two memory deallocation primitives even use the same heap!)
[16.10] In p = new Fred(), does the Fred memory "leak" if the Fred
constructor throws an exception?
No.
If an exception occurs during the Fred constructor of p = new Fred(), the C++
language guarantees that the memory sizeof(Fred) bytes that were allocated
will automagically be released back to the heap.
Here are the details: new Fred() is a two-step process:
The statement marked "Placement new" calls the Fred constructor. The pointer p
becomes the this pointer inside the constructor, Fred::Fred().
Any time you allocate an array of objects via new (usually with the [n] in the new
expression), you must use [] in the delete statement. This syntax is necessary
because there is no syntactic difference between a pointer to a thing and a
pointer to an array of things (something we inherited from C).
[16.13] Can I drop the [] when deleteing array of some built-in type
(char, int, etc)?
No!
Sometimes programmers think that the [] in the delete[] p only exists so the
compiler will call the appropriate destructors for all elements in the array.
Because of this reasoning, they assume that an array of some built-in type such
as char or int can be deleted without the []. E.g., they assume the following is
valid code:
void userCode(int n)
{
char* p = new char[n];
...
delete p; // ← ERROR! Should be delete[] p!
}
But the above code is wrong, and it can cause a disaster at runtime. In particular,
the code that's called for delete p is operator delete(void*), but the code
that's called for delete[] p is operator delete[](void*). The default behavior
for the latter is to call the former, but users are allowed to replace the latter with a
different behavior (in which case they would normally also replace the
corresponding new code in operator new[](size_t)). If they replaced the
delete[] code so it wasn't compatible with the delete code, and you called the
wrong one (i.e., if you said delete p rather than delete[] p), you could end up
with a disaster at runtime.
[16.14] After p = new Fred[n], how does the compiler know there are
n objects to be destructed during delete[] p?
Short answer: Magic.
Long answer: The run-time system stores the number of objects, n, somewhere
where it can be retrieved if you only know the pointer, p. There are two popular
techniques that do this. Both these techniques are in use by commercial-grade
compilers, both have tradeoffs, and neither is perfect. These techniques are:
• Over-allocate the array and put n just to the left of the first Fred object.
• Use an associative array with p as the key and n as the value.
As long as you're careful, it's OK for an object to commit suicide ( delete this).
1. You must be absolutely 100% positive sure that this object was allocated
via new (not by new[], nor by placement new, nor a local object on the
stack, nor a global, nor a member of another object; but by plain ordinary
new).
2. You must be absolutely 100% positive sure that your member function will
be the last member function invoked on this object.
3. You must be absolutely 100% positive sure that the rest of your member
function (after the delete this line) doesn't touch any piece of this object
(including calling any other member functions or touching any data
members).
4. You must be absolutely 100% positive sure that no one even touches the
this pointer itself after the delete this line. In other words, you must not
examine it, compare it with another pointer, compare it with NULL, print it,
cast it, do anything with it.
Naturally the usual caveats apply in cases where your this pointer is a pointer to
a base class when you don't have a virtual destructor.
void manipulateArray()
{
const unsigned nrows = 10; // Num rows is a compile-time constant
const unsigned ncols = 20; // Num columns is a compile-time constant
Fred matrix[nrows][ncols];
More commonly, the size of the matrix isn't known until run-time but you know
that it will be rectangular. In this case you need to use the heap ("freestore"), but
at least you are able to allocate all the elements in one freestore chunk.
}
catch (...) {
// Make sure to do the delete when an exception is thrown:
delete[] matrix;
throw; // Re-throw the current exception
}
Finally at the other extreme, you may not even be guaranteed that the matrix is
rectangular. For example, if each row could have a different length, you'll need to
allocate each row individually. In the following function, ncols[i] is the number of
columns in row number i, where i varies between 0 and nrows-1 inclusive.
}
catch (...) {
// Make sure to do the delete when an exception is thrown:
// Note that some of these matrix[...] pointers might be
// NULL, but that's okay since it's legal to delete NULL.
for (unsigned i = nrows; i > 0; --i)
delete[] matrix[i-1];
delete[] matrix;
throw; // Re-throw the current exception
}
Note the funny use of matrix[i-1] in the deletion process. This prevents wrap-
around of the unsigned value when i goes one step below zero.
Finally, note that pointers and arrays are evil. It is normally much better to
encapsulate your pointers in a class that has a safe and simple interface. The
following FAQ shows how to do this.
[16.17] But the previous FAQ's code is SOOOO tricky and error
prone! Isn't there a simpler way?
Yep.
The reason the code in the previous FAQ was so tricky and error prone was that
it used pointers, and we know that pointers and arrays are evil. The solution is to
encapsulate your pointers in a class that has a safe and simple interface. For
example, we can define a Matrix class that handles a rectangular matrix so our
user code will be vastly simplified when compared to the the rectangular matrix
code from the previous FAQ:
The main thing to notice is the lack of clean-up code. For example, there aren't
any delete statements in the above code, yet there will be no memory leaks,
assuming only that the Matrix destructor does its job correctly.
class Matrix {
public:
Matrix(unsigned nrows, unsigned ncols);
// Throws a BadSize object if either size is zero
class BadSize { };
private:
unsigned nrows_, ncols_;
Fred* data_;
};
Matrix::~Matrix()
{
delete[] data_;
}
Note that the above Matrix class accomplishes two things: it moves some tricky
memory management code from the user code (e.g., main()) to the class, and it
reduces the overall bulk of program. The latter point is important. For example,
assuming Matrix is even mildly reusable, moving complexity from the users
[plural] of Matrix into Matrix itself [singular] is equivalent to moving complexity
from the many to the few. Anyone who's seen Star Trek 2 knows that the good of
the many outweighs the good of the few... or the one.
[16.18] But the above Matrix class is specific to Fred! Isn't there a
way to make it generic?
Now it's easy to use Matrix<T> for things other than Fred. For example, the
following uses a Matrix of std::string (where std::string is the standard string
class):
#include <string>
You can thus get an entire family of classes from a template. For example,
Matrix<Fred>, Matrix<std::string>, Matrix< Matrix<std::string> >, etc.
private:
unsigned nrows_, ncols_;
T* data_;
};
template<typename T>
inline T& Matrix<T>::operator() (unsigned row, unsigned col)
{
if (row >= nrows_ || col >= ncols_) throw BoundsViolation();
return data_[row*ncols_ + col];
}
template<typename T>
inline const T& Matrix<T>::operator() (unsigned row, unsigned col) con
st
{
if (row >= nrows_ || col >= ncols_)
throw BoundsViolation();
return data_[row*ncols_ + col];
}
template<typename T>
inline Matrix<T>::Matrix(unsigned nrows, unsigned ncols)
: nrows_ (nrows)
, ncols_ (ncols)
//, data_ <--initialized below (after the 'if/throw' statement)
{
if (nrows == 0 || ncols == 0)
throw BadSize();
data_ = new T[nrows * ncols];
}
template<typename T>
inline Matrix<T>::~Matrix()
{
delete[] data_;
}
#include <vector>
private:
std::vector<std::vector<T> > data_;
};
template<typename T>
inline unsigned Matrix<T>::nrows() const
{ return data_.size(); }
template<typename T>
inline unsigned Matrix<T>::ncols() const
{ return data_[0].size(); }
template<typename T>
inline T& Matrix<T>::operator() (unsigned row, unsigned col)
{
if (row >= nrows() || col >= ncols()) throw BoundsViolation();
return data_[row][col];
}
template<typename T>
inline const T& Matrix<T>::operator() (unsigned row, unsigned col) con
st
{
if (row >= nrows() || col >= ncols()) throw BoundsViolation();
return data_[row][col];
}
template<typename T>
Matrix<T>::Matrix(unsigned nrows, unsigned ncols)
: data_ (nrows)
{
if (nrows == 0 || ncols == 0)
throw BadSize();
for (unsigned i = 0; i < nrows; ++i)
data_[i].resize(ncols);
}
Note how much simpler this is than the previous: there is no explicit new in the
constructor, and there is no need for any of The Big Three (destructor, copy
constructor or assignment operator). Simply put, your code is a lot less likely to
have memory leaks if you use std::vector than if you use explicit new T[n] and
delete[] p.
Note also that std::vector doesn't force you to allocate numerous chunks of
memory. If you prefer to allocate only one chunk of memory for the entire matrix,
as was done in the previous, just change the type of data_ to std::vector<T>
and add member variables nrows_ and ncols_. You'll figure out the rest: initialize
data_ using data_(nrows * ncols), change operator()() to return
data_[row*ncols_ + col];, etc.
Yes, in the sense that the standard library has a std::vector template that
provides this behavior.
No, in the sense that built-in array types need to have their length specified at
compile time.
Yes, in the sense that even built-in array types can specify the first index bounds
at run-time. E.g., comparing with the previous FAQ, if you only need the first
array dimension to vary then you can just ask new for an array of arrays, rather
than an array of pointers to arrays:
You can't do this if you need anything other than the first dimension of the array
to change at run-time.
But please, don't use arrays unless you have to. Arrays are evil. Use some object
of some class if you can. Use arrays only when you have to.
As usual with the Named Constructor Idiom, the constructors are all private or
protected, and there are one or more public static create() methods (the so-
called "named constructors"), one per constructor. In this case the create()
methods allocate the objects via new. Since the constructors themselves are not
public, there is no other way to create objects of the class.
class Fred {
public:
// The create() methods are the "named constructors":
static Fred* create() { return new Fred(); }
static Fred* create(int i) { return new Fred(i); }
static Fred* create(const Fred& fred) { return new Fred(fred); }
...
private:
// The constructors themselves are private or protected:
Fred();
Fred(int i);
Fred(const Fred& fred);
...
};
int main()
{
Fred* p = Fred::create(5);
...
delete p;
...
}
Make sure your constructors are in the protected section if you expect Fred to
have derived classes.
Note also that you can make another class Wilma a friend of Fred if you want to
allow a Wilma to have a member object of class Fred, but of course this is a
softening of the original goal, namely to force Fred objects to be allocated via
new.
If all you want is the ability to pass around a bunch of pointers to the same
object, with the feature that the object will automagically get deleted when the
last pointer to it disappears, you can use something like the following "smart
pointer" class:
// Fred.h
class FredPtr;
class Fred {
public:
Fred() : count_(0) /*...*/ { } // All ctors set count_ to 0 !
...
private:
friend class FredPtr; // A friend class
unsigned count_;
// count_ must be initialized to 0 by all constructors
// count_ is the number of FredPtr objects that point at this
};
class FredPtr {
public:
Fred* operator-> () { return p_; }
Fred& operator* () { return *p_; }
FredPtr(Fred* p) : p_(p) { ++p_->count_; } // p must not be NULL
~FredPtr() { if (--p_->count_ == 0) delete p_; }
FredPtr(const FredPtr& p) : p_(p.p_) { ++p_->count_; }
FredPtr& operator= (const FredPtr& p)
{ // DO NOT CHANGE THE ORDER OF THESE STATEMENTS!
// (This order properly handles self-assignment)
// (This order also properly handles recursion, e.g., if a Fred contains FredPtr
s)
Fred* const old = p_;
p_ = p.p_;
++p_->count_;
if (--old->count_ == 0) delete old;
return *this;
}
private:
Fred* p_; // p_ is never NULL
};
Note that you can soften the "never NULL" rule above with a little more checking
in the constructor, copy constructor, assignment operator, and destructor. If you
do that, you might as well put a p_ != NULL check into the "*" and "->" operators
(at least as an assert()). I would recommend against an operator Fred*()
method, since that would let people accidentally get at the Fred*.
One of the implicit constraints on FredPtr is that it must only point to Fred objects
which have been allocated via new. If you want to be really safe, you can enforce
this constraint by making all of Fred's constructors private, and for each
constructor have a public (static) create() method which allocates the Fred
object via new and returns a FredPtr (not a Fred*). That way the only way anyone
could create a Fred object would be to get a FredPtr ("Fred* p = new Fred()"
would be replaced by "FredPtr p = Fred::create()"). Thus no one could
accidentally subvert the reference counting mechanism.
For example, if Fred had a Fred::Fred() and a Fred::Fred(int i, int j), the
changes to class Fred would be:
class Fred {
public:
static FredPtr create(); // Defined below class FredPtr {
...};
static FredPtr create(int i, int j); // Defined below class FredPtr {
...};
...
private:
Fred();
Fred(int i, int j);
...
};
The end result is that you now have a way to use simple reference counting to
provide "pointer semantics" for a given object. Users of your Fred class explicitly
use FredPtr objects, which act more or less like Fred* pointers. The benefit is
that users can make as many copies of their FredPtr "smart pointer" objects, and
the pointed-to Fred object will automagically get deleted when the last such
FredPtr object vanishes.
If you'd rather give your users "reference semantics" rather than "pointer
semantics," you can use reference counting to provide "copy on write".
The basic idea is to allow users to think they're copying your Fred objects, but in
reality the underlying implementation doesn't actually do any copying unless and
until some user actually tries to modify the underlying Fred object.
Class Fred::Data houses all the data that would normally go into the Fred class.
Fred::Data also has an extra data member, count_, to manage the reference
counting. Class Fred ends up being a "smart reference" that (internally) points to
a Fred::Data.
class Fred {
public:
...
private:
class Data {
public:
Data();
Data(int i, int j);
Data(const Data& d);
unsigned count_;
// count_ is the number of Fred objects that point at this
// count_ must be initialized to 1 by all constructors
// (it starts as 1 since it is pointed to by the Fred object that created it)
};
Data* data_;
};
Fred::Fred(const Fred& f)
: data_(f.data_)
{
++data_->count_;
}
Fred::~Fred()
{
if (--data_->count_ == 0) delete data_;
}
void Fred::sampleMutatorMethod()
{
// This method might need to change things in *data_
// Thus it first checks if this is the only pointer to *data_
if (data_->count_ > 1) {
Data* d = new Data(*data_); // Invoke Fred::Data's copy ctor
--data_->count_;
data_ = d;
}
assert(data_->count_ == 1);
If it is fairly common to call Fred's default constructor, you can avoid all those new
calls by sharing a common Fred::Data object for all Freds that are constructed
via Fred::Fred(). To avoid static initialization order problems, this shared
Fred::Data object is created "on first use" inside a function. Here are the
changes that would be made to the above code (note that the shared Fred::Data
object's destructor is never invoked; if that is a problem, either hope you don't
have any static initialization order problems, or drop back to the approach
described above):
class Fred {
public:
...
private:
...
static Data* defaultData();
};
Fred::Fred()
: data_(defaultData())
{
++data_->count_;
}
Fred::Data* Fred::defaultData()
{
static Data* p = NULL;
if (p == NULL) {
p = new Data();
++p->count_; // Make sure it never goes to zero
}
return p;
}
Note: You can also provide reference counting for a hierarchy of classes if your
Fred class would normally have been a base class.
• [17.1] What are some ways try / catch / throw can improve software
quality?
• [17.2] How can I handle a constructor that fails?
• [17.3] How can I handle a destructor that fails?
• [17.4] How should I handle resources if my constructors may throw
exceptions?
• [17.5] How do I change the string-length of an array of char to prevent
memory leaks even if/when someone throws an exception?
• [17.6] What should I throw?
• [17.7] What should I catch?
• [17.8] But MFC seems to encourage the use of catch-by-pointer; should I
do the same? UPDATED!
• [17.9] What does throw; (without an exception object after the throw
keyword) mean? Where would I use it?
• [17.10] How do I throw polymorphically?
• [17.11] When I throw this object, how many times will it be copied?
• [17.12] Exception handling seems to make my life more difficult; clearly
I'm not the problem, am I??
• [17.13] I have too many try blocks; what can I do about it?
[17.1] What are some ways try / catch / throw can improve software
quality?
The commonly used alternative to try / catch / throw is to return a return code
(sometimes called an error code) that the caller explicitly tests via some
conditional statement such as if. For example, printf(), scanf() and malloc()
work this way: the caller is supposed to test the return value to see if the function
succeeded.
Although the return code technique is sometimes the most appropriate error
handling technique, there are some nasty side effects to adding unnecessary if
statements:
So compared to error reporting via return-codes and if, using try / catch / throw
is likely to result in code that has fewer bugs, is less expensive to develop, and
has faster time-to-market. Of course if your organization doesn't have any
experiential knowledge of try / catch / throw, you might want to use it on a toy
project first just to make sure you know what you're doing — you should always
get used to a weapon on the firing range before you bring it to the front lines of a
shooting war.
Throw an exception.
Constructors don't have a return type, so it's not possible to use return codes.
The best way to signal constructor failure is therefore to throw an exception. If
you don't have the option of using exceptions, the "least bad" work-around is to
put the object into a "zombie" state by setting an internal status bit so the object
acts sort of like it's dead even though it is technically still alive.
The idea of a "zombie" object has a lot of down-side. You need to add a query
("inspector") member function to check this "zombie" bit so users of your class
can find out if their object is truly alive, or if it's a zombie (i.e., a "living dead"
object), and just about every place you construct one of your objects (including
within a larger object or an array of objects) you need to check that status flag via
an if statement. You'll also want to add an if to your other member functions: if
the object is a zombie, do a no-op or perhaps something more obnoxious.
In practice the "zombie" thing gets pretty ugly. Certainly you should prefer
exceptions over zombie objects, but if you do not have the option of using
exceptions, zombie objects might be the "least bad" alternative.
The C++ rule is that you must never throw an exception from a destructor that is
being called during the "stack unwinding" process of another exception. For
example, if someone says throw Foo(), the stack will be unwound so all the
stack frames between the throw Foo() and the } catch (Foo e) { will get
popped. This is called stack unwinding.
During stack unwinding, all the local objects in all those stack frames are
destructed. If one of those destructors throws an exception (say it throws a Bar
object), the C++ runtime system is in a no-win situation: should it ignore the Bar
and end up in the } catch (Foo e) { where it was originally headed? Should it
ignore the Foo and look for a } catch (Bar e) { handler? There is no good
answer — either choice loses information.
So the C++ language guarantees that it will call terminate() at this point, and
terminate() kills the process. Bang you're dead.
The easy way to prevent this is never throw an exception from a destructor. But if
you really want to be clever, you can say never throw an exception from a
destructor while processing another exception. But in this second case, you're in
a difficult situation: the destructor itself needs code to handle both throwing an
exception and doing "something else", and the caller has no guarantees as to
what might happen when the destructor detects an error (it might throw an
exception, it might do "something else"). So the whole solution is harder to write.
So the easy thing to do is always do "something else". That is, never throw an
exception from a destructor.
Of course the word never should be "in quotes" since there is always some
situation somewhere where the rule won't hold. But certainly at least 99% of the
time this is a good rule of thumb.
Every data member inside your object should clean up its own mess.
By the way, if you think your Fred class is going to be allocated into a smart
pointer, be nice to your users and create a typedef within your Fred class:
#include <memory>
class Fred {
public:
typedef std::auto_ptr<Fred> Ptr;
...
};
That typedef simplifies the syntax of all the code that uses your objects: your
users can say Fred::Ptr instead of std::auto_ptr<Fred>:
#include "Fred.h"
void g()
{
std::auto_ptr<Fred> p1( new Fred() ); // explicit but verbose
Fred::Ptr p2( new Fred() ); // simpler
...
}
If what you really want to do is work with strings, don't use an array of char in the
first place, since arrays are evil. Instead use an object of some string-like class.
For example, suppose you want to get a copy of a string, fiddle with the copy,
then append another string to the end of the fiddled copy. The array-of- char
approach would look something like this:
}
catch (...) {
delete[] copy; // we got an exception; prevent a memory leak
throw; // re-throw the current exception
}
Using char*s like this is tedious and error prone. Why not just use an object of
some string class? Your compiler probably supplies a string-like class, and it's
probably just as fast and certainly it's a lot simpler and safer than the char* code
that you would have to write yourself. For example, if you're using the
std::string class from the standardization committee, your code might look
something like this:
The char* version requires you to write around three times more code than you
would have to write with the std::string version. Most of the savings came from
std::string's automatic memory management: in the std::string version, we
didn't need to write any code...
C++, unlike just about every other language with exceptions, is very
accomodating when it comes to what you can throw. In fact, you can throw
anything you like. That begs the question then, what should you throw?
Generally, it's best to throw objects, not built-ins. If possible, you should throw
instances of classes that derive (ultimately) from the std::exception class. By
making your exception class inherit (ultimately) from the standard exception
base-class, you are making life easier for your users (they have the option of
catching most things via std::exception), plus you are probably providing them
with more information (such as the fact that your particular exception might be a
refinement of std::runtime_error or whatever).
#include <stdexcept>
void f()
{
// ...
throw MyException();
}
In keeping with the C++ tradition of "there's more than one way to do that"
(translation: "give programmers options and tradeoffs so they can decide what's
best for them in their situation"), C++ allows you a variety of options for catching.
In fact, you have all the flexibility that you have in declaring function parameters,
and the rules for whether a particular exception matches (i.e., will be caught by) a
particular catch clause are almost exactly the same as the rules for parameter
compatibility when calling a function.
Given all this flexibility, how do you decide what to catch? Simple: unless there's
a good reason not to, catch by reference. Avoid catching by value, since that
causes a copy to be made and the copy can have different behavior from what
was thrown. Only under very special circumstances should you catch by pointer.
Depends. If you're using MFC and catching one of their exceptions, by all means,
do it their way. Same goes for any framework: when in Rome, do as the Romans.
Don't try to force a framework into your way of thinking, even if "your" way of
thinking is "better." If you decide to use a framework, embrace its way of thinking
— use the idioms that its authors expected you to use.
But if you're creating your own framework and/or a piece of the system that does
not directly depend on MFC, then don't catch by pointer just because MFC does
it that way. When you're not in Rome, you don't necessarily do as the Romans. In
this case, you should not. Libraries like MFC predated the standardization of
exception handling in the C++ language, and some of these libraries use a
backwards-compatible form of exception handling that requires (or at least
encourages) you to catch by pointer.
The problem with catching by pointer is that it's not clear who (if anyone) is
responsible for deleting the pointed-to object. For example, consider the
following:
MyException x;
void f()
{
MyException y;
try {
switch ((rand() >> 8) % 3) { // the ">> 8" (typically) improves the period of the l
owest 2 bits
case 0: throw new MyException;
case 1: throw &x;
case 2: throw &y;
}
}
catch (MyException* p) {
... ← should we delete p here or not???!?
}
}
This isn't to say it's not possible to work through these issues. The point is simply
this: if you catch by reference rather than by pointer, life is easier. Why make life
hard when you don't have to?
The moral: avoid throwing pointer expressions, and avoid catching by pointer,
unless you're using an existing library that "wants" you to do so.
[17.9] What does throw; (without an exception object after the throw
keyword) mean? Where would I use it?
class MyException {
public:
...
void addInfo(const std::string& info);
...
};
void f()
{
try {
...
}
catch (MyException& e) {
e.addInfo("f() failed");
throw;
}
}
In this example, the statement throw; means "re-throw the current exception."
Here, a function caught an exception (by non-const reference), modified the
exception (by adding information to it), and then re-threw the exception. This
idiom can be used to implement a simple form of stack-trace, by adding
appropriate catch clauses in the important functions of your program.
void handleException()
{
try {
throw;
}
catch (MyException& e) {
...code to handle MyException...
}
catch (YourException& e) {
...code to handle YourException...
}
}
void f()
{
try {
...something that might throw...
}
catch (...) {
handleException();
}
}
class MyExceptionBase { };
void f(MyExceptionBase& e)
{
// ...
throw e;
}
void g()
{
MyExceptionDerived e;
try {
f(e);
}
catch (MyExceptionDerived& e) {
...code to handle MyExceptionDerived...
}
catch (...) {
...code to handle other exceptions...
}
}
If you try this, you might be surprised at run-time when your catch (...) clause is
entered, and not your catch (MyExceptionDerived&) clause. This happens
because you didn't throw polymorphically. In function f(), the statement throw
e; throws an object with the same type as the static type of the expression e. In
other words, it throws an instance of MyExceptionBase. The throw statement
behaves as-if the thrown object is copied, as opposed to making a "virtual copy".
class MyExceptionBase {
public:
virtual void raise();
};
void MyExceptionBase::raise()
{ throw *this; }
void MyExceptionDerived::raise()
{ throw *this; }
void f(MyExceptionBase& e)
{
// ...
e.raise();
}
void g()
{
MyExceptionDerived e;
try {
f(e);
}
catch (MyExceptionDerived& e) {
...code to handle MyExceptionDerived...
}
catch (...) {
...code to handle other exceptions...
}
}
Note that the throw statement has been moved into a virtual function. The
statement e.raise() will exhibit polymorphic behavior, since raise() is declared
virtual and e was passed by reference. As before, the thrown object will be of
the static type of the argument in the throw statement, but within
MyExceptionDerived::raise(), that static type is MyExceptionDerived, not
MyExceptionBase.
[17.11] When I throw this object, how many times will it be copied?
Objects that are thrown must have a publicly accessible copy-constructor. The
compiler is allowed to generate code that copies the thrown object any number of
times, including zero. However even if the compiler never actually copies the
thrown object, it must make sure the exception class's copy constructor exists
and is accessible.
The C++ exception handling mechanism can be powerful and useful, but if you
use it with the wrong mindset, the result can be a mess. If you're getting bad
results, for instance, if your code seems unnecessarily convoluted or overly
cluttered with try blocks, you might be suffering from a "wrong mindset." This
FAQ gives you a list of some of those wrong mindsets.
Warning: do not be simplistic about these "wrong mindsets." They are guidelines
and ways of thinking, not hard and fast rules. Sometimes you will do the exact
opposite of what they recommend — do not write me about some situation that is
an exception (no pun intended) to one or more of them — I guarantee that there
are exceptions. That's not the point.
There are other "wrong exception-handling mindsets," but hopefully those will
help you out. And remember: don't take those as hard and fast rules. They are
guidelines, and there are exceptions to each.
You might have the mindset of return codes even though you are using the
syntax of try/catch/throw. For instance, you might put a try block around just
about every call:
void myCode()
{
try {
foo();
}
catch (FooException& e) {
...
}
try {
bar();
}
catch (BarException& e) {
...
}
try {
baz();
}
catch (BazException& e) {
...
}
}
Although this uses the try/catch/throw syntax, the overall structure is very
similar to the way things are done with return codes, and the consequent
software development/test/maintenance costs are basically the same as they
were for return codes. In other words, this approach doesn't buy you much over
using return codes. In general, it is bad form.
One way out is to ask yourself this question for each try block: "Why am I using a
try block here?" There are several possible answers:
• Your answer might be, "So I can actually handle the exception. My catch
clause deals with the error and continues execution without throwing any
additional exceptions. My caller never knows that the exception occurred.
My catch clause does not throw any exceptions and it does not return any
error-codes." In that case, you leave the try block as-is — it is probably
good.
• Your answer might be, "So I can have a catch clause that does blah blah
blah, after which I will rethrow the exception." In this case, consider
changing the try block into an object whose destructor does blah blah
blah. For instance, if you have a try block whose catch clause closes a file
then rethrows the exception, consider replacing the whole thing with a
File object whose destructor closes the file. This is commonly called RAII.
• Your answer might be, "So I can repackage the exception: I catch a
XyzException, extract the details, then throw a PqrException." When that
happens, consider a better hierarchy of exception objects that doesn't
require this catch/repackage/rethrow idea. This often involves broadening
the meaning of XyzException, though obviously you shouldn't go too far.
• There are other answers as well, but the above are some common ones
that I've seen.
Main point is to ask "Why?". If you discover the reason you're doing it, you might
find that there are better ways to achieve your goal.
Having said all this, there are, unfortunately, some people who have the return-
code-mindset burned so deeply into their psyche that they just can't seem to see
any alternatives. If that is you, there is still hope: get a mentor. If you see it done
right, you'll probably get it. Style is sometimes caught, not just taught.
A good thing. It means using the keyword const to prevent const objects from
getting mutated.
For example, if you wanted to create a function f() that accepted a std::string,
plus you want to promise callers not to change the caller's std::string that gets
passed to f(), you can have f() receive its std::string parameter...
The lack of const in these functions tells the compiler that they are allowed to
(but are not required to) change the caller's std::string object. Thus they can
pass their std::string to any of the f() functions, but only f3() (the one that
receives its parameter "by value") can pass its std::string to g1() or g2(). If
f1() or f2() need to call either g() function, a local copy of the std::string
object must be passed to the g() function; the parameter to f1() or f2() cannot
be directly passed to either g() function. E.g.,
std::string localCopy = s;
g1(localCopy); // OK since localCopy is not const
}
Naturally in the above case, any changes that g1() makes are made to the
localCopy object that is local to f1(). In particular, no changes will be made to
the const parameter that was passed by reference to f1().
If you find ordinary type safety helps you get systems correct (it does; especially
in large systems), you'll find const correctness helps also.
It means p points to an object of class Fred, but p can't be used to change that
Fred object (naturally p could also be NULL).
For example, if class Fred has a const member function called inspect(), saying
p->inspect() is OK. But if class Fred has a non-const member function called
mutate(), saying p->mutate() is an error (the error is caught by the compiler; no
run-time tests are done, which means const doesn't slow your program down).
[18.5] What's the difference between "const Fred* p", "Fred* const p"
and "const Fred* const p"?
• const Fred* p means "p points to a Fred that is const" — that is, the Fred
object can't be changed via p.
• Fred* const p means "p is a const pointer to a Fred" — that is, you can
change the Fred object via p, but you can't change the pointer p itself.
• const Fred* const p means "p is a const pointer to a const Fred" — that
is, you can't change the pointer p itself, nor can you change the Fred
object via p.
It means x aliases a Fred object, but x can't be used to change that Fred object.
For example, if class Fred has a const member function called inspect(), saying
x.inspect() is OK. But if class Fred has a non-const member function called
mutate(), saying x.mutate() is an error (the error is caught by the compiler; no
run-time tests are done, which means const doesn't slow your program down).
No, it is nonsense.
To find out what the above declaration means, you have to read it right-to-left.
Thus "Fred& const x" means "x is a const reference to a Fred". But that is
redundant, since references are always const. You can't reseat a reference.
Never. With or without the const.
In other words, "Fred& const x" is functionally equivalent to "Fred& x". Since
you're gaining nothing by adding the const after the &, you shouldn't add it since
it will confuse people. I.e., the const will make some people think that the Fred is
const, as if you had said "const Fred& x".
Answer: absolutely no one should pretend they can make decisions for your
organization until they know something about your organization. One size does
not fit all; there is no "right" answer for all organizations, so do not allow anyone
to make a knee-jerk decision in either direction. "Think" is not a four-letter word.
For example, some organizations value consistency and have tons of code using
const Fred&; for those, Fred const& would be a bad decision independent of its
merits. There are lots of other business scenarios, some of which produce a
preference for Fred const&, others a preference for const Fred&.
You'll need to overcome a little inertia to go with Fred const&. Most current C++
books use const Fred&, most programmers learned C++ with that syntax, and
most programmers still use that syntax. That doesn't mean const Fred& is
necessarily better for your organization, but it does mean you may get some
confusion and mistakes during the transition and/or when you integrate new
people. Some organizations are convinced the benefits of Fred const& outweigh
the costs; others, apparently, are not.
Another caveat: if you decide to use Fred const& x, do something to make sure
your people don't mis-type it as the nonsensical "Fred& const x".
Answer: absolutely no one should pretend they can make decisions for your
organization until they know something about your organization. One size does
not fit all; there is no "right" answer for all organizations, so do not allow anyone
to make a knee-jerk decision in either direction. "Think" is not a four-letter word.
For example, some organizations value consistency and have tons of code using
const Fred*; for those, Fred const* would be a bad decision independent of its
merits. There are lots of other business scenarios, some of which produce a
preference for Fred const*, others a preference for const Fred*.
You'll need to overcome a little inertia to go with Fred const*. Most current C++
books use const Fred*, most programmers learned C++ with that syntax, and
most programmers still use that syntax. That doesn't mean const Fred* is
necessarily better for your organization, but it does mean you may get some
confusion and mistakes during the transition and/or when you integrate new
people. Some organizations are convinced the benefits of Fred const* outweigh
the costs; others, apparently, are not.
Another caveat: if you decide to use Fred const* x, do something to make sure
your people don't mis-type it as the semantically different but syntactically similar
"Fred* const x". Those two forms have completely different meanings even
though they look similar at first blush.
A const member function is indicated by a const suffix just after the member
function's parameter list. Member functions with a const suffix are called "const
member functions" or "inspectors." Member functions without a const suffix are
called "non-const member functions" or "mutators."
class Fred {
public:
void inspect() const; // This member promises NOT to change *this
void mutate(); // This member function might change *this
};
The trailing const on inspect() member function means that the abstract (client-
visible) state of the object isn't going to change. This is slightly different from
promising that the "raw bits" of the object's struct aren't going to change. C++
compilers aren't allowed to take the "bitwise" interpretation unless they can solve
the aliasing problem, which normally can't be solved (i.e., a non- const alias could
exist which could modify the state of the object). Another (important) insight from
this aliasing issue: pointing at an object with a pointer-to- const doesn't guarantee
that the object won't change; it promises only that the object won't change via
that pointer.
class Person {
public:
const std::string& name_good() const; ← Right: the caller can't change the na
me
std::string& name_evil() const; ← Wrong: the caller can change the na
me
...
};
void myCode(const Person& p) ← You're promising not to change the Person objec
t...
{
p.name_evil() = "Igor"; ← ...but you changed it anyway!!
}
The good news is that the compiler will often catch you if you get this wrong. In
particular, if you accidentally return a member of your this object by non-const
reference, such as in Person::name_evil() above, the compiler will often detect
it and give you a compile-time error while compiling the innards of, in this case,
Person::name_evil().
The bad news is that the compiler won't always catch you: there are some cases
where the compiler simply won't ever give you a compile-time error message.
Net: you need to think, and you need to remember the guideline in this FAQ. If
the thing you are returning by reference is logically part of your this object,
independent of whether it is physically embedded within your this object, then a
const method needs to return by const reference or by value, but not by non-
const reference. (The idea of "logically" part of your this object is related to the
notion of an object's "abstract state"; see the previous FAQ for more.)
It's when you have an inspector method and a mutator method with the same
name and the same number and type of parameters — the methods differ only in
that one is const and the other is non-const.
class MyFredList {
public:
const Fred& operator[] (unsigned index) const; ← subscript operators often
come in pairs
Fred& operator[] (unsigned index); ← subscript operators often
come in pairs
...
};
When you apply the subscript operator to a MyFredList object that is non-const,
the compiler will call the non-const subscript operator. Since that returns a
normal Fred&, you can both inspect and mutate the corresponding Fred object.
For example, suppose class Fred has an inspector called Fred::inspect()
const and a mutator Fred::mutate():
However when you apply the subscript operator to a const MyFredList object,
the compiler will call the const subscript operator. Since that returns a const
Fred&, you can inspect the corresponding Fred object, but you can't
mutate/change it:
You can, of course, also use const-overloading for things other than the
subscript operator.
When this happens, the data member which will be modified should be marked
as mutable (put the mutable keyword just before the data member's declaration;
i.e., in the same place where you could put const). This tells the compiler that the
data member is allowed to change during a const member function. If your
compiler doesn't support the mutable keyword, you can cast away the const'ness
of this via the const_cast keyword (but see the NOTE below before doing this).
E.g., in Set::lookup() const, you might say,
After this line, self will have the same bits as this (e.g., self == this), but self
is a Set* rather than a const Set* (technically a const Set* const, but the right-
most const is irrelevant to this discussion). Therefore you can use self to modify
the object pointed to by this.
NOTE: there is an extremely unlikely error that can occur with const_cast. It only
happens when three very rare things are combined at the same time: a data
member that ought to be mutable (such as is discussed above), a compiler that
doesn't support the mutable keyword, and an object that was originally defined to
be const (as opposed to a normal, non-const object that is pointed to by a
pointer-to-const). Although this combination is so rare that it may never happen
to you, if it ever did happen the code may not work (the Standard says the
behavior is undefined).
If you ever want to use const_cast, use mutable instead. In other words, if you
ever need to change a member of an object, and that object is pointed to by a
pointer-to-const, the safest and simplest thing to do is add mutable to the
member's declaration. You can use const_cast if you are sure that the actual
object isn't const (e.g., if you are sure the object is declared something like this:
Set s;), but if the object itself might be const (e.g., if it might be declared like:
const Set s;), use mutable rather than const_cast.
Please don't write and tell me that version X of compiler Y on machine Z allows
you to change a non-mutable member of a const object. I don't care — it is illegal
according to the language and your code will probably fail on a different compiler
or even a different version (an upgrade) of the same compiler. Just say no. Use
mutable instead.
Even if the language outlawed const_cast, the only way to avoid flushing the
register cache across a const member function call would be to solve the aliasing
problem (i.e., to prove that there are no non- const pointers that point to the
object). This can happen only in rare cases (when the object is constructed in the
scope of the const member function invocation, and when all the non- const
member function invocations between the object's construction and the const
member function invocation are statically bound, and when every one of these
invocations is also inlined, and when the constructor itself is inlined, and when
any member functions the constructor calls are inline).
[18.15] Why does the compiler allow me to change an int after I've
pointed at it with a const int*?
Because "const int* p" means "p promises not to change the *p," not "*p
promises not to change."
Causing a const int* to point to an int doesn't const-ify the int. The int can't
be changed via the const int*, but if someone else has an int* (note: no const)
that points to ("aliases") the same int, then that int* can be used to change the
int. For example:
int main()
{
int x = 5;
f(&x, &x); // This is perfectly legal (and even moral!)
...
}
Note that main() and f(const int*,int*) could be in different compilation units
that are compiled on different days of the week. In that case there is no way the
compiler can possibly detect the aliasing at compile time. Therefore there is no
way we could make a language rule that prohibits this sort of thing. In fact, we
wouldn't even want to make such a rule, since in general it's considered a feature
that you can have many pointers pointing to the same thing. The fact that one of
those pointers promises not to change the underlying "thing" is just a promise
made by the pointer; it's not a promise made by the "thing".
"const Fred* p" means that the Fred can't be changed via pointer p, but there
might be other ways to get at the object without going through a const (such as
an aliased non-const pointer such as a Fred*). For example, if you have two
pointers "const Fred* p" and "Fred* q" that point to the same Fred object
(aliasing), pointer q can be used to change the Fred object but pointer p cannot.
class Fred {
public:
void inspect() const; // A const member function
void mutate(); // A non-const member function
};
int main()
{
Fred f;
const Fred* p = &f;
Fred* q = &f;
...
}
C++ allows the (safe) conversion Foo* → const Foo*, but gives an error if you try
to implicitly convert Foo** → const Foo**.
The rationale for why that error is a good thing is given below. But first, here is
the most common solution: simply change const Foo** to const Foo* const*:
int main()
{
Foo** p = /*...*/;
...
f(p); // ERROR: it's illegal and immoral to convert Foo** to const Foo**
g(p); // OK: it's legal and moral to convert Foo** to const Foo* const*
...
}
The reason the conversion from Foo** → const Foo** is dangerous is that it
would let you silently and accidentally modify a const Foo object without a cast:
class Foo {
public:
void modify(); // make some modify to the this object
};
int main()
{
const Foo x;
Foo* p;
const Foo** q = &p; // q now points to p; this is (fortunately!) an error
*q = &x; // p now points to x
p->modify(); // Ouch: modifies a const Foo!!
...
}
Reminder: please do not pointer-cast your way around this. Just Say No!
Yep.
As a specification device.
Human beings abstract things on two dimensions: part-of and kind-of. A Ford
Taurus is-a-kind-of-a Car, and a Ford Taurus has-a Engine, Tires, etc. The part-
of hierarchy has been a part of software since the ADT style became relevant;
inheritance adds "the other" major dimension of decomposition.
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
Yes.
An object of a derived class is a kind of the base class. Therefore the conversion
from a derived class pointer to a base class pointer is perfectly safe, and
happens all the time. For example, if I am pointing at a car, I am in fact pointing
at a vehicle, so converting a Car* to a Vehicle* is perfectly safe and normal:
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
Derived classes do not get access to private members of a base class. This
effectively "seals off" the derived class from any changes made to the private
members of the base class.
A class has two distinct interfaces for two distinct sets of clients:
Unless you expect all your derived classes to be built by your own team, you
should declare your base class's data members as private and use protected
inline access functions by which derived classes will access the private data in
the base class. This way the private data declarations can change, but the
derived class's code won't break (unless you change the protected access
functions).
Nope.
Whenever someone says to you, "You should always make data private," stop
right there — it's an "always" or "never" rule, and those rules are what I call one-
size-fits-all rules. The real world isn't that simple.
Here's the way I say it: if I expect derived classes, I should ask this question: who
will create them? If the people who will create them will be outside your team, or
if there are a huge number of derived classes, then and only then is it worth
creating a protected interface and using private data. If I expect the derived
classes to be created by my own team and to be reasonable in number, it's just
not worth the trouble: use protected data. And hold your head up, don't be
ashamed: it's the right thing to do!
The benefit of protected access functions is that you won't break your derived
classes as often as you would if your data was protected. Put it this way: if you
believe your users will be outside your team, you should do a lot more than just
provide get/set methods for your private data. You should actually create another
interface. You have a public interface for one set of users, and a protected
interface for another set of users. But they both need an interface that is carefully
designed — designed for stability, usability, performance, etc. And at the end of
the day, the real benefit of privatizing your data (including providing an interface
that is coherent and, as much as possible, opaque) is to avoid breaking your
derived classes when you change that data structure.
But if your own team is creating the derived classes, and there are a reasonably
small number of them, it's simply not worth the effort: use protected data. Some
purists (translation: people who've never stepped foot in the real world, people
who've spent their entire lives in an ivory tower, people who don't understand
words like "customer" or "schedule" or "deadline" or "ROI") think that everything
ought to be reusable and everything ought to have a clean, easy to use interface.
Those kinds of people are dangerous: they often make your project late, since
they make everything equally important. They're basically saying, "We have 100
tasks, and I have carefully prioritized them: they are all priority 1." They make the
notion of priority meaningless.
You simply will not have enough time to make life easy for everyone, so the very
best you can do is make life easy for a subset of the world. Prioritize. Select the
people that matter most and spend time making stable interfaces for them. You
may not like this, but everyone is not created equal; some people actually do
matter more than others. We have a word for those important people. We call
them "customers."
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Every interface you build has a cost and a benefit. Every reusable component
you build has a cost and a benefit. Every test case, every cleanly structured
thing-a-ma-bob, every investment of any sort. You should never invest any time
or any money in any thing if there is not a positive return on that investment. If it
costs your company more than it saves, don't do it!
Not everyone agrees with me on this; they have a right to be wrong. For
example, people who live sufficiently far from the real world act like every
investment is good. After all, they reason, if you wait long enough, it might
someday save somebody some time. Maybe. We hope.
That whole line of reasoning is unprofessional and irresponsible. You don't have
infinite time, so invest it wisely. Sure, if you live in an ivory tower, you don't have
to worry about those pesky things called "schedules" or "customers." But in the
real world, you work within a schedule, and you must therefore invest your time
only where you'll get good pay-back.
Back to the original question: when should you invest time in building a protected
interface? Answer: when you get a good return on that investment. If it's going to
cost you an hour, make sure it saves somebody more than an hour, and make
sure the savings isn't "someday over the rainbow." If you can save an hour within
the current project, it's a no-brainer: go for it. If it's going to save some other
project an hour someday maybe we hope, then don't do it. And if it's in between,
your answer will depend on exactly how your company trades off the future
against the present.
The point is simple: do not do something that could damage your schedule. (Or if
you do, make sure you never work with me; I'll have your head on a platter.)
Investing is good if there's a pay-back for that investment. Don't be naive and
childish; grow up and realize that some investments are bad because they, in
balance, cost more than they return.
The derived class can either fully replace ("override") the base class member
function, or the derived class can partially replace ("augment") the base class
member function. The latter is accomplished by having the derived class member
function call the base class member function, if desired.
When you have a pointer to an object, the object may actually be of a class that
is derived from the class of the pointer (e.g., a Vehicle* that is actually pointing
to a Car object; this is called "polymorphism"). Thus there are two types: the
(static) type of the pointer (Vehicle, in this case), and the (dynamic) type of the
pointed-to object (Car, in this case).
Static typing means that the legality of a member function invocation is checked
at the earliest possible moment: by the compiler at compile time. The compiler
uses the static type of the pointer to determine whether the member function
invocation is legal. If the type of the pointer can handle the member function,
certainly the pointed-to object can handle it as well. E.g., if Vehicle has a certain
member function, certainly Car also has that member function since Car is a kind-
of Vehicle.
Dynamic binding means that the address of the code in a member function
invocation is determined at the last possible moment: based on the dynamic type
of the object at run time. It is called "dynamic binding" because the binding to the
code that actually gets called is accomplished dynamically (at run time). Dynamic
binding is a result of virtual functions.
Non-virtual member functions are resolved statically. That is, the member
function is selected statically (at compile-time) based on the type of the pointer
(or reference) to the object.
The compiler creates a v-table for each class that has at least one virtual
function. For example, if class Circle has virtual functions for draw() and
move() and resize(), there would be exactly one v-table associated with class
Circle, even if there were a gazillion Circle objects, and the v-pointer of each of
those Circle objects would point to the Circle v-table. The v-table itself has
pointers to each of the virtual functions in the class. For example, the Circle v-
table would have three pointers: a pointer to Circle::draw(), a pointer to
Circle::move(), and a pointer to Circle::resize().
During a dispatch of a virtual function, the run-time system follows the object's
v-pointer to the class's v-table, then follows the appropriate slot in the v-table to
the method code.
The space-cost overhead of the above technique is nominal: an extra pointer per
object (but only for objects that will need to do dynamic binding), plus an extra
pointer per method (but only for virtual methods). The time-cost overhead is also
fairly nominal: compared to a normal function call, a virtual function call
requires two extra fetches (one to get the value of the v-pointer, a second to get
the address of the method). None of this runtime activity happens with non-
virtual functions, since the compiler resolves non- virtual functions exclusively
at compile-time based on the type of the pointer.
Note: the above discussion is simplified considerably, since it doesn't account for
extra structural things like multiple inheritance, virtual inheritance, RTTI, etc.,
nor does it account for space/speed issues such as page faults, calling a function
via a pointer-to-function, etc. If you want to know about those other things,
please ask comp.lang.c++; PLEASE DO NOT SEND E-MAIL TO ME!
Let's work an example. Suppose class Base has 5 virtual functions: virt0()
through virt4().
class Base {
public:
virtual arbitrary_return_type virt0(...arbitrary params...);
virtual arbitrary_return_type virt1(...arbitrary params...);
virtual arbitrary_return_type virt2(...arbitrary params...);
virtual arbitrary_return_type virt3(...arbitrary params...);
virtual arbitrary_return_type virt4(...arbitrary params...);
...
};
Step #1: the compiler builds a static table containing 5 function-pointers, burying
that table into static memory somewhere. Many (not all) compilers define this
table while compiling the .cpp that defines Base's first non-inline virtual function.
We call that table the v-table; let's pretend its technical name is Base::__vtable.
If a function pointer fits into one machine word on the target hardware platform,
Base::__vtable will end up consuming 5 hidden words of memory. Not 5 per
instance, not 5 per function; just 5. It might look something like the following
pseudo-code:
// Pseudo-code (not C++, not C) for a static table defined within file Base.cpp
Step #2: the compiler adds a hidden pointer (typically also a machine-word) to
each object of class Base. This is called the v-pointer. Think of this hidden pointer
as a hidden data member, as if the compiler rewrites your class to something like
this:
class Base {
public:
...
FunctionPtr* __vptr; ← supplied by the compiler, hidden from the programmer
...
};
Step #3: the compiler initializes this->__vptr within each constructor. The idea
is to cause each object's v-pointer to point at its class's v-table, as if it adds the
following instruction in each constructor's init-list:
Base::Base(...arbitrary params...)
: __vptr(&Base::__vtable[0]) ← supplied by the compiler, hidden from the progra
mmer
...
{
...
}
Now let's work out a derived class. Suppose your C++ code defines class Der
that inherits from class Base. The compiler repeats steps #1 and #3 (but not #2).
In step #1, the compiler creates a hidden v-table, keeping the same function-
pointers as in Base::__vtable but replacing those slots that correspond to
overrides. For instance, if Der overrides virt0() through virt2() and inherits the
others as-is, Der's v-table might look something like this (pretend Der doesn't add
any new virtuals):
// Pseudo-code (not C++, not C) for a static table defined within file Der.cpp
Finally, let's see how the compiler implements a call to a virtual function. Your
code might look like this:
void mycode(Base* p)
{
p->virt3();
}
void mycode(Base* p)
{
p->__vptr[3](p);
}
1. The first load gets the v-pointer, storing it into a register, say r1.
2. The second load gets the word at r1 + 3*4 (pretend function-pointers are
4-bytes long, so r1+12 is the pointer to the right class's virt3() function).
Pretend it puts that word into register r2 (or r1 for that matter).
3. The third instruction calls the code at location r2.
Conclusions:
Use Base::f();
Let's start with a simple case. When you call a non-virtual function, the compiler
obviously doesn't use the virtual-function mechanism. Instead it calls the function
by name, using the fully qualified name of the member function. For instance, the
following C++ code...
void mycode(Fred* p)
{
p->goBowling(); ← pretend Fred::goBowling() is non-virtual
}
...might get compiled into something like this C-like code (the p parameter
becomes the this object within the member function):
void mycode(Fred* p)
{
__Fred__goBowling(p); ← pseudo-code only; not real
}
The actual name-mangling scheme is more involved that the simple one implied
above, but you get the idea. The point is that there is nothing strange about this
particular case — it resolves to a normal function more-or-less like printf().
Now for the case being addressed in the question above: When you call a virtual
function using its fully-qualified name (the class-name followed by " ::"), the
compiler does not use the virtual call mechanism, but instead uses the same
mechanism as if you called a non-virtual function. Said another way, it calls the
function by name rather than by slot-number. So if you want code within derived
class Der to call Base::f(), that is, the version of f() defined in its base class
Base, you should write:
void Der::f()
{
Base::f(); ← or, if you prefer, this->Base::f();
}
The complier will turn that into something vaguely like the following (again using
an overly simplistic name-mangling scheme):
Suppose there is a base class Vehicle with derived classes Car and Truck. The
code traverses a list of Vehicle objects and does different things depending on
the type of Vehicle. For example it might weigh the Truck objects (to make sure
they're not carrying too heavy of a load) but it might do something different with a
Car object — check the registration, for example.
The initial solution for this, at least with most people, is to use an if statement.
E.g., "if the object is a Truck, do this, else if it is a Car, do that, else do a third
thing":
typedef std::vector<Vehicle*> VehicleList;
void myCode(VehicleList& v)
{
for (VehicleList::iterator p = v.begin(); p != v.end(); ++p) {
Vehicle& v = **p; // just for shorthand
The problem with this is what I call "else-if-heimer's disease" (say it fast and you'll
understand). The above code gives you else-if-heimer's disease because
eventually you'll forget to add an else if when you add a new derived class, and
you'll probably have a bug that won't be detected until run-time, or worse, when
the product is in the field.
The solution is to use dynamic binding rather than dynamic typing. Instead of
having (what I call) the live-code dead-data metaphor (where the code is alive
and the car/truck objects are relatively dead), we move the code into the data.
This is a slight variation of Bertrand Meyer's Law of Inversion.
The idea is simple: use the description of the code within the {...} blocks of each
if (in this case it is "the foo-bar operation"; obviously your name will be different).
Just pick up this descriptive name and use it as the name of a new virtual
member function in the base class (in this case we'll add a fooBar() member
function to class Vehicle).
class Vehicle {
public:
// performs the "foo-bar" operation
virtual void fooBar() = 0;
};
Then you remove the whole if...else if... block and replace it with a simple call
to this virtual function:
void myCode(VehicleList& v)
{
for (VehicleList::iterator p = v.begin(); p != v.end(); ++p) {
Vehicle& v = **p; // just for shorthand
Finally you move the code that used to be in the {...} block of each if into the
fooBar() member function of the appropriate derived class:
void Car::fooBar()
{
// car-specific code that does "foo-bar" on 'this'
... ← this is the code that was in {...} of if (v is a Car)
}
void Truck::fooBar()
{
// truck-specific code that does "foo-bar" on 'this'
... ← this is the code that was in {...} of if (v is a Truck)
}
If you actually have an else block in the original myCode() function (see above for
the "semi-generic code that does the 'foo-bar' operation on something other than
a Car or Truck"), change Vehicle's fooBar() from pure virtual to plain virtual and
move the code into that member function:
class Vehicle {
public:
// performs the "foo-bar" operation
virtual void fooBar();
};
void Vehicle::fooBar()
{
// semi-generic code that does "foo-bar" on something else
... ← this is the code that was in {...} of the else
// you can think of this as "default" code...
}
That's it!
The point, of course, is that we try to avoid decision logic with decisions based on
the kind-of derived class you're dealing with. In other words, you're trying to avoid
if the object is a car do xyz, else if it's a truck do pqr, etc., because
that leads to else-if-heimer's disease.
Confused? Here's a simplified rule of thumb that usually protects you and usually
doesn't cost you anything: make your destructor virtual if your class has any
virtual functions. Rationale:
• that usually protects you because most base classes have at least one
virtual function.
• that usually doesn't cost you anything because there is no added per-
object space-cost for the second or subsequent virtual in your class. In
other words, you've already paid all the per-object space-cost that you'll
ever pay once you add the first virtual function, so the virtual
destructor doesn't add any additional per-object space cost. (Everything in
this bullet is theoretically compiler-specific, but in practice it will be valid on
almost all compilers.)
Note: if your base class has a virtual destructor, then your destructor is
automatically virtual. You might need an explicit destructor for other reasons,
but there's no need to redeclare a destructor simply to make sure it is virtual.
No matter whether you declare it with the virtual keyword, declare it without the
virtual keyword, or don't declare it at all, it's still virtual.
BTW, if you're interested, here are the mechanical details of why you need a
virtual destructor when someone says delete using a Base pointer that's
pointing at a Derived object. When you say delete p, and the class of p has a
virtual destructor, the destructor that gets invoked is the one associated with
the type of the object *p, not necessarily the one associated with the type of the
pointer. This is A Good Thing. In fact, violating that rule makes your program
undefined. The technical term for that is, "Yuck."
An idiom that allows you to do something that C++ doesn't directly support.
You can get the effect of a virtual constructor by a virtual clone() member
function (for copy constructing), or a virtual create() member function (for the
default constructor).
class Shape {
public:
virtual ~Shape() { } // A virtual destructor
virtual void draw() = 0; // A pure virtual function
virtual void move() = 0;
...
virtual Shape* clone() const = 0; // Uses the copy constructor
virtual Shape* create() const = 0; // Uses the default constructor
};
void userCode(Shape& s)
{
Shape* s2 = s.clone();
Shape* s3 = s.create();
...
delete s2; // You need a virtual destructor here
delete s3;
}
This function will work correctly regardless of whether the Shape is a Circle,
Square, or some other kind-of Shape that doesn't even exist yet.
Note: If you are using Microsoft Visual C++ 6.0, you need to change the return
types in the derived classes to Shape*. This is because MS VC++ 6.0 does not
support this feature of the language. Please do not write me about this; the
above code is correct with respect to the C++ Standard (see 10.3p5); the
problem is with MS VC++ 6.0. Fortunately covariant return types are properly
supported by MS VC++ 7.0.
• [21.1] Should I hide member functions that were public in my base class?
• [21.2] Converting Derived* → Base* works OK; why doesn't Derived** →
Base** work?
• [21.3] Is a parking-lot-of-Car a kind-of parking-lot-of-Vehicle?
• [21.4] Is an array of Derived a kind-of array of Base?
• [21.5] Does array-of-Derived is-not-a-kind-of array-of-Base mean arrays
are bad?
• [21.6] Is a Circle a kind-of an Ellipse?
• [21.7] Are there other options to the "Circle is/isnot kind-of Ellipse"
dilemma?
• [21.8] But I have a Ph.D. in Mathematics, and I'm sure a Circle is a kind of
an Ellipse! Does this mean Marshall Cline is stupid? Or that C++ is stupid?
Or that OO is stupid?
• [21.9] Perhaps Ellipse should inherit from Circle then?
• [21.10] But my problem doesn't have anything to do with circles and
ellipses, so what good is that silly example to me?
• [21.11] How could "it depend"??!? Aren't terms like "Circle" and "Ellipse"
defined mathematically?
• [21.12] If SortedList has exactly the same public interface as List, is
SortedList a kind-of List?
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
C++ allows the conversion Derived* → Base*, since a Derived object is a kind of
a Base object. However trying to convert Derived** → Base** is flagged as an
error. Although this error may not be obvious, it is nonetheless a good thing. For
example, if you could convert Car** → Vehicle**, and if you could similarly
convert NuclearSubmarine** → Vehicle**, you could assign those two pointers
and end up making a Car* point at a NuclearSubmarine:
class Vehicle {
public:
virtual ~Vehicle() { }
virtual void startEngine() = 0;
};
int main()
{
Car car;
Car* carPtr = &car;
Car** carPtrPtr = &carPtr;
Vehicle** vehiclePtrPtr = carPtrPtr; // This is an error in C++
NuclearSubmarine sub;
NuclearSubmarine* subPtr = ⊂
*vehiclePtrPtr = subPtr;
// This last line would have caused carPtr to point to sub !
carPtr->openGasCap(); // This might call fireNuclearMissle()!
...
}
In other words, if it were legal to convert Derived** → Base**, the Base** could
be dereferenced (yielding a Base*), and the Base* could be made to point to an
object of a different derived class, which could cause serious problems for
national security (who knows what would happen if you invoked the
openGasCap() member function on what you thought was a Car, but in reality it
was a NuclearSubmarine!! Try the above code out and see what it does — on
most compilers it will call NuclearSubmarine::fireNuclearMissle()!
(BTW you'll need to use a pointer cast to get it to compile. Suggestion: try to
compile it without a pointer cast to see what the compiler does. If you're really
quiet when the error message appears on the screen, you should be able to hear
the muffled voice of your compiler pleading with you, "Please don't use a pointer
cast! Pointer casts prevent me from telling you about errors in your code, but
they don't make your errors go away! Pointer casts are evil!" At least that's what
my compiler says.)
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
Nope.
I know it sounds strange, but it's true. You can think of this as a direct
consequence of the previous FAQ, or you can reason it this way: if the kind-of
relationship were valid, then someone could point a parking-lot-of- Vehicle
pointer at a parking-lot-of-Car, which would allow someone to add any kind of
Vehicle to a parking-lot-of-Car (assuming parking-lot-of-Vehicle has a member
function like add(Vehicle&)). In other words, you could park a Bicycle,
SpaceShuttle, or even a NuclearSubmarine in a parking-lot-of-Car. Certainly it
would be surprising if someone accessed what they thought was a Car from the
parking-lot-of-Car, only to find that it is actually a NuclearSubmarine. Gee, I
wonder what the openGasCap() method would do??
Perhaps this will help: a container of Thing is not a kind-of container of Anything
even if a Thing is a kind-of an Anything. Swallow hard; it's true.
You don't have to like it. But you do have to accept it.
One last example which we use in our OO/C++ training courses: "A Bag-of-Apple
is not a kind-of Bag-of-Fruit." If a Bag-of-Apple could be passed as a Bag-of-
Fruit, someone could put a Banana into the Bag, even though it is supposed to
only contain Apples!
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
Nope.
This is a corollary of the previous FAQ. Unfortunately this one can get you into a
lot of hot water. Consider this:
class Base {
public:
virtual void f(); // 1
};
int main()
{
Derived arrayOfDerived[10]; // 4
userCode(arrayOfDerived); // 5
...
}
The root problem is that C++ can't distinguish between a pointer-to-a-thing and a
pointer-to-an-array-of-things. Naturally C++ "inherited" this feature from C.
NOTE: If we had used an array-like class (e.g., std::vector<Derived> from the
standard library) instead of using a raw array, this problem would have been
properly trapped as an error at compile time rather than a run-time disaster.
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
Seriously, arrays are very closely related to pointers, and pointers are notoriously
difficult to deal with. But if you have a complete grasp of why the above few
FAQs were a problem from a design perspective (e.g., if you really know why a
container of Thing is not a kind-of container of Anything), and if you think
everyone else who will be maintaining your code also has a full grasp on these
OO design truths, then you should feel free to use arrays. But if you're like most
people, you should use a template container class such as std::vector<T> from
the standard library rather than raw arrays.
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
Depends. But not if Ellipse guarantees it can change its size asymmetrically.
For example, if Ellipse has a setSize(x,y) member function that promises the
object's width() will be x and its height() will be y, Circle can't be a kind-of
Ellipse. Simply put, if Ellipse can do something Circle can't, then Circle can't
be a kind of Ellipse.
In the second case, class Oval could only have setSize(size) which sets both
the width() and the height() to size. Ellipse and Circle could both inherit from
Oval. Ellipse —but not Circle— could add the setSize(x,y) operation (but
beware of the hiding rule if the same member function name setSize() is used
for both operations).
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
[21.7] Are there other options to the "Circle is/isnot kind-of Ellipse"
dilemma?
If you claim that all Ellipses can be squashed asymmetrically, and you claim
that Circle is a kind-of Ellipse, and you claim that Circle can't be squashed
asymmetrically, clearly you've got to revoke one of your claims. You can get rid
of Ellipse::setSize(x,y), get rid of the inheritance relationship between Circle
and Ellipse, or admit that your Circles aren't necessarily circular. You can also
get rid of Circle completely, where circleness is just a temporary state of an
Ellipse object rather than a permanent quality of the object.
Here are the two most common traps new OO/C++ programmers regularly fall
into. They attempt to use coding hacks to cover up a broken design, e.g., they
might redefine Circle::setSize(x,y) to throw an exception, call abort(),
choose the average of the two parameters, or to be a no-op. Unfortunately all
these hacks will surprise users, since users are expecting width() == x and
height() == y. The one thing you must not do is surprise your users.
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
Actually, it doesn't mean any of these things. But I'll tell you what it does mean —
you may not like what I'm about to say: it means your intuitive notion of "kind of"
is leading you to make bad inheritance decisions. Your tummy is lying to you
about what good inheritance really means — stop believing those lies.
You must make the base class weaker (weaken Ellipse to the point that it no
longer guarantees you can set its width and height to different values), make the
derived class stronger (empower a Circle with the ability to be both symmetric
and, ahem, asymmetric), or admit that a Circle is not substitutable for Ellipse.
Important: there really are no other choices than the above three. In particular:
1. PLEASE don't write me and tell me that a fourth option is to derive both
Circle and Ellipse from a third common base class. That's not a fourth
solution. That's just a repackaging of solution #3: it works precisely
because it removes the inheritance relationship between Circle and
Ellipse.
2. PLEASE don't write me and tell me that a fourth option is to prevent users
from changing the dimensions of an "Ellipse." That is not a fourth solution.
That's just a repackaging of solution #1: it works precisely because it
removes that guarantee that setSize(x,y) actually sets the width and
height.
3. PLEASE don't write me and tell me that you've decided one of these three
is "the best" solution. Doing that would show you had missed the whole
point of this FAQ, specifically that bad inheritance is subtle but fortunately
you have three (not one; not two; but three) possible ways to dig yourself
out. So when you run into bad inheritance, please try all three of these
techniques and select the best, perhaps "least bad," of the three. Don't
throw out two of these tools ahead of time: try them all.
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
(Note: some people correctly point out that a constant Circle is substitutable for
a constant Ellipse. That's true, but it's really not a fourth option: it's really just a
special case of option #1, since it works precisely because a constant Ellipse
doesn't have a setSize(x,y) method.)
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
If Circle is the base class and Ellipse is the derived class, then you run into a
whole new set of problems. For example, suppose Circle has a radius()
method. Then Ellipse will also need to have a radius() method, but that doesn't
make much sense: what does it even mean for a possibly assymetric ellipse to
have a radius?
If you get over that hurdle, such as by having Ellipse::radius() return the
average of the major and minor axes or whatever, then there is a problem with
the relationship between radius() and area(). Suppose Circle has an area()
method that promises to return 3.14159[etc] times the square whatever radius()
returns. Then either Ellipse::area() will not return the true area of the ellipse,
or you'll have to stand on your head to get radius() to return something that
matches the above formula.
Even if you get past that one, such as by having Ellipse::radius() return the
square root of the ellipse's area divided by pi, you'll get stuck by the
circumference() method. Suppose Circle has a circumference() method that
promises to return two times pi times whatever is returned by radius(). Now
you're stuck: there's no way to make all those constraints work out for Ellipse:
the Ellipse class will have to lie about its area, its circumference, or both.
Bottom line: you can make anything inherit from anything provided the methods
in the derived class abide by the promises made in the base class. But you ought
not to use inheritance just because you feel like it, or just because you want to
get code reuse. You should use inheritance (a) only if the derived class's
methods can abide by all the promises made in the base class, and (b) only if
you don't think you'll confuse your users, and (c) only if there's something to be
gained by using the inheritance — some real, measurable improvement in time,
money or risk.
Ahhh, there's the rub. You think the Circle/Ellipse example is just a silly
example. But in reality, your problem is an isomorphism to that example.
I don't care what your inheritance problem is, but all —yes all— bad inheritances
boil down to the Circle-is-not-a-kind-of-Ellipse example.
Here's why: Bad inheritances always have a base class with an extra capability
(often an extra member function or two; sometimes an extra promise made by
one or a combination of member functions) that a derived class can't satisfy.
You've either got to make the base class weaker, make the derived class
stronger, or eliminate the proposed inheritance relationship. I've seen lots and
lots and lots of these bad inheritance proposals, and believe me, they all boil
down to the Circle/Ellipse example.
(Note: this FAQ has to do with public inheritance; private and protected
inheritance are different.)
[21.11] How could "it depend"??!? Aren't terms like "Circle" and
"Ellipse" defined mathematically?
It's irrelevant that those terms are defined mathematically. That irrelevance is
why "it depends."
The first step in any rational discussion is to define terms. In this case, the first
step is to define the terms Circle and Ellipse. Believe it or not, most heated
disagreements over whether class Circle should/shouldn't inherit from class
Ellipse are caused by incompatible definitions of those terms.
The key insight is to forget mathematics and "the real world," and instead accept
as final the only definitions that are relevant for answering the question: the
classes themselves. Take Ellipse. You created a class with that name, so the
one and only final arbiter of what you meant by that term is your class. People
who try to mix "the real world" into the discussion get hopelessly confused, and
often get into heated (and, sadly, meaningless) arguments.
Since so many people just don't get it, here's an example. Suppose your program
says class Foo : public Bar { ... }. This defines what you mean by the term
Foo: the one, final, unambiguous, precise definition of Foo is given by unioning
the public parts of Foo with the public parts of its base class, Bar. Now suppose
you decide to rename Bar to Ellipse and Foo to Circle. This means that you
(yes you; not "mathematics"; not "history"; not "precedence" nor Euclid nor Euler
nor any other famous mathematician; little old you) have defined the meaning of
the term Circle within your program. If you defined it in a way that didn't
correspond to people's intuitive notion of circles, then you probably should have
chosen a better label for your class, but nonetheless your definition is the one,
final, unambiguous, precise definition of the term Circle in your program. If
somebody else outside your program defines the same term differently, that
other definition is irrelevant to questions about your program, even if the
"somebody else" is Euclid. Within your program, you define the terms, and the
term Circle is defined by your class named Circle.
Simply put, when we are asking questions about words defined in your program,
we must use your definitions of those terms, not Euclid's. That is why the ultimate
answer to the question is "it depends." It depends because the answer to
whether the thing your program calls Circle is properly substitutable for the thing
your program calls Ellipse depends on exactly how your program defines those
terms. It's ridiculous and misleading to use Euclid's definition when trying to
answer questions about your classes in your program; we must use your
definitions.
When someone gets heated about this, I always suggest changing the labels to
terms that have no predetermined connotations, such as Foo and Bar. Since
those terms do not evoke any mathematical relationships, people naturally go to
the class definition to find out exactly what the programmer had in mind. But as
soon as we rename the class from Foo to Circle, some people suddenly think
they can control the meaning of the term; they're wrong and silly. The definition of
the term is still spelled out exclusively by the class itself, not by any outside
entity.
Next insight: inheritance means "is substitutable for." It does not mean "is a"
(since that is ill defined) and it does not mean "is a kind of" (also ill defined).
Substitutability is well defined: to be substitutable, the derived class is allowed
(not required) to add (not remove) public methods, and for each public method
inherited from the base class, the derived class is allowed (not required) to
weaken preconditions and/or strengthen postconditions (not the other way
around). Further the derived class is allowed to have completely different
constructors, static methods, and non-public methods.
Back to Ellipse and Circle: if you define the term Ellipse to mean something
that can be resized asymmetrically (e.g., its methods let you change the width
and height independently and guarantee that the width and height will actually
change to the specified values), then that is the final, precise definition of the
term Ellipse. If you define the thing called Circle as something that cannot be
resized asymmetrically, then that is also your prerogative, and it is the final,
precise definition of the term Circle. If you defined those terms in that way, then
obviously the thing you called Circle is not substitutable for the thing you called
Ellipse, therefore the inheritance would be improper. QED.
So the answer is always "it depends." In particular, it depends on the behaviors
of the base and derived classes. It does not depend on the name of the base and
derived classes, since those are arbitrary labels. (I'm not advocating sloppy
names; I am, however, saying that you must not use your intuitive connotation of
a name to assume you know what a class does. A class does what it does, not
what you think it ought to do based on its name.)
It bothers (some) people that the thing you called Circle might not be
substitutable for the thing you called Ellipse, and to those people I have only
two things to say: (a) get over it, and (b) change the labels of the classes if that
makes you feel more comfortable. For example, rename Ellipse to
ThingThatCanBeResizedAssymetrically and Circle to
ThingThatCannotBeResizedAssymetrically.
Unfortunately I honestly believe that people who feel better after renaming the
things are missing the point. The point is this: in OO, a thing is defined by how it
behaves, not by the label used to name it. Obviously it's important to choose
good names, but even so, the name chosen does not define the thing. The
definition of the thing is specified by the public methods, including the contracts
(preconditions and postconditions) of those methods. Inheritance is proper or
improper based on the classes' behaviors, not their names.
Probably not.
The most important insight is that the answer depends on the details of the base
class's contract. It is not enough to know that the public interfaces / method
signatures are compatible; one also needs to know if the contracts / behaviors
are compatible.
The important part of the previous sentence are the words "contracts /
behaviors." That phrase goes well beyond the public interface = method
signatures = method names and parameter types and constness. A method's
contract means its advertised behavior = advertised requirements and promises
= advertised preconditions and postconditions. So if the base class has a method
void insert(const Foo& x), the contract of that method includes the signature
(meaning the name insert and the parameter const Foo&), but goes well beyond
that to include the method's advertised preconditions and postconditions.
The derived class must do what the base class promises, not what it actually
does.
The key is that we've separated the advertised behavior ("specification") from
implemented behavior ("implementation"), and we rely on the specification rather
than the implementation. This is very important because in a large percentage of
the cases the base class's method is an unimplemented pure virtual — the only
thing that can be relied on is the specification — there simply is no
implementation on which to rely.
Back to SortedList and List: it seems likely that List has one or more methods
that have contracts which guarantee order, and therefore SortedList is probably
not a kind-of List. For example, if List has a method that lets you reorder things,
prepend things, append things, or change the ith element, and if those methods
make the typical advertised promise, then SortedList would need to violate that
advertised behavior and the inheritance would be improper. But it all depends on
what the base class advertises — on the base class's contract.
Since interfaces are so valuable, they should be protected from being tarnished
by data structures and other implementation artifacts. Thus you should separate
interface from implementation.
Use an ABC.
A member function declaration that turns a normal class into an abstract class
(i.e., an ABC). You normally only implement it in a derived class.
Some member functions exist in concept; they don't have any reasonable
definition. E.g., suppose I asked you to draw a Shape at location (x,y) that has
size 7. You'd ask me "what kind of shape should I draw?" (circles, squares,
hexagons, etc, are drawn differently). In C++, we must indicate the existence of
the draw() member function (so users can call it when they have a Shape* or a
Shape&), but we recognize it can (logically) be defined only in derived classes:
class Shape {
public:
virtual void draw() const = 0; // = 0 means it is "pure virtual"
...
};
This pure virtual function makes Shape an ABC. If you want, you can think of the
"= 0;" syntax as if the code were at the NULL pointer. Thus Shape promises a
service to its users, yet Shape isn't able to provide any code to fulfill that promise.
This forces any actual object created from a [concrete] class derived from Shape
to have the indicated member function, even though the base class doesn't have
enough information to actually define it yet.
Note that it is possible to provide a definition for a pure virtual function, but this
usually confuses novices and is best avoided until later.
If the class "owns" the object pointed to by the (abstract) base class pointer, use
the Virtual Constructor Idiom in the (abstract) base class. As usual with this
idiom, we declare a pure virtual clone() method in the base class:
class Shape {
public:
...
virtual Shape* clone() const = 0; // The Virtual (Copy) Constructor
...
};
Then we implement this clone() method in each derived class. Here is the code
for derived class Circle:
(Note: the return type in the derived class is intentionally different from the one in
the base class.)
Now suppose that each Fred object "has-a" Shape object. Naturally the Fred
object doesn't know whether the Shape is Circle or a Square or ... Fred's copy
constructor and assignment operator will invoke Shape's clone() method to copy
the object:
class Fred {
public:
// p must be a pointer returned by new; it must not be NULL
Fred(Shape* p)
: p_(p) { assert(p != NULL); }
~Fred()
{ delete p_; }
Fred(const Fred& f)
: p_(f.p_->clone()) { }
Fred& operator= (const Fred& f)
{
if (this != &f) { // Check for self-assignment
Shape* p2 = f.p_->clone(); // Create the new one FIRST...
delete p_; // ...THEN delete the old one
p_ = p2;
}
return *this;
}
...
private:
Shape* p_;
};
Yes. It's sometimes (not always!) a great idea. For example, suppose all Shape
objects have a common algorithm for printing, but this algorithm depends on their
area and they all have a potentially different way to compute their area. In this
case Shape's area() method would necessarily have to be virtual (probably
pure virtual) but Shape::print() could, if we were guaranteed no derived class
wanted a different algorithm for printing, be a non-virtual defined in the base
class Shape.
#include "Shape.h"
[23.2] That last FAQ confuses me. Is it a different strategy from the
other ways to use virtual functions? What's going on?
Yes, it is a different strategy. Yes, there really are two different basic ways to use
virtual functions:
1. Suppose you have the situation described in the previous FAQ: you have
a method whose overall structure is the same for each derived class, but
has little pieces that are different in each derived class. So the algorithm is
the same, but the primitives are different. In this case you'd write the
overall algorithm in the base class as a public method (that's sometimes
non-virtual), and you'd write the little pieces in the derived classes. The
little pieces would be declared in the base class (they're often protected,
they're often pure virtual, and they're certainly virtual), and they'd
ultimately be defined in each derived class. The most critical question in
this situation is whether or not the public method containing the overall
algorithm should be virtual. The answer is to make it virtual if you think
that some derived class might need to override it.
2. Suppose you have the exact opposite situation from the previous FAQ,
where you have a method whose overall structure is different in each
derived class, yet it has little pieces that are the same in most (if not all)
derived classes. In this case you'd put the overall algorithm in a public
virtual that's ultimately defined in the derived classes, and the little
pieces of common code can be written once (to avoid code duplication)
and stashed somewhere (anywhere!). A common place to stash the little
pieces is in the protected part of the base class, but that's not necessary
and it might not even be best. Just find a place to stash them and you'll be
fine. Note that if you do stash them in the base class, you should normally
make them protected, since normally they do things that public users
don't need/want to do. Assuming they're protected, they probably
shouldn't be virtual: if the derived class doesn't like the behavior in one
of them, it doesn't have to call that method.
For emphasis, the above list is a both/and situation, not an either/or situation. In
other words, you don't have to choose between these two strategies on any
given class. It's perfectly normal to have method f() correspond to strategy #1
while method g() corresponds to strategy #2. In other words, it's perfectly normal
to have both strategies working in the same class.
[Recently connected in the (previously named) "Public Overloaded Non-Virtuals Call Protected
Non-Overloaded Virtuals" Idiom (in 3/06) and fixed a typo in the code (f_double is now f_dbl)
thanks to Al-Asham Said (in 9/06). Click here to go to the next FAQ in the "chain" of recent
changes.]
First, stay away from always/never rules, and instead use whichever approach is
the best fit for the situation. There are at least two good reasons to use protected
virtuals (see below), but just because you are sometimes better off with protected
virtuals does not mean you should always use them. Consistency and symmetry
are good up to a point, but at the end of the day the most important metrics are
cost + schedule + risk, and unless an idea materially improves cost and/or
schedule and/or risk, it's just symmetry for symmetry's sake (or consistency for
consistency's sake, etc.).
The cheapest + fastest + lowest risk approach in my experience ends up
resulting in most virtuals being public, with protected virtuals being used
whenever you have either of these two cases: the situation discussed in FAQ
[23.2], or the situation discussed in FAQ [23.9].
The latter deserves some additional commentary. Pretend you have a base class
with a set of overloaded virtuals. To make the example easy, pretend there are
just two: virtual void f(int) and virtual void f(double). The idea of the
Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals idiom is
to change the public overloaded methods to non-virtuals, and make those call
protected non-overloaded virtuals.
class Base {
public:
virtual void f(int x); ← may or may not be pure virtual
virtual void f(double x); ← may or may not be pure virtual
};
Improving this via the Public Overloaded Non-Virtuals Call Protected Non-
Overloaded Virtuals idiom:
class Base {
public:
void f(int x) { f_int(x); } ← non-virtual
void f(double x) { f_dbl(x); } ← non-virtual
protected:
virtual void f_int(int);
virtual void f_dbl(double);
};
Here's an overview of the improved code that uses the Public Overloaded Non-
Virtuals Call Protected Non-Overloaded Virtuals idiom:
The reason I and others use this idiom is to make life easier and less error-prone
for the developers of the derived classes. Remember the goals stated above:
schedule + cost + risk? Let's evaluate this Idiom in light of those goals. From a
cost/schedule standpoint, the base class (singular) is slightly larger but the
derived classes (plural) are slightly smaller, for a net (small) improvement in
schedule and cost. The more signicant improvement is in risk: the idiom packs
the complexity of properly managing the hiding rule into the base class (singular).
This means the derived classes (plural) more-or-less automatically handle the
hiding rule, so the various developers who produce those derived classes can
remain almost completely focused on the details of the derived classes
themselves — they need not concern themselves with the (subtle and often
misunderstood) hiding rule. This greatly reduces the chance that the writers of
the derived classes will screw up the hiding-rule.
With apologies to Spock, the good of the many (the derived classes (plural))
outweighs the good of the one (the base class (singular)).
(See FAQ [23.9] for why you need to be careful about overriding some-but-not-all
of a set of overloaded methods, and therefore why the above makes life easier
on derived classes.)
Almost never.
Protected virtuals are okay, but private virtuals are usually a net loss. Reason:
private virtuals confuse new C++ programmers, and confusion increases cost,
delays schedule, and degrades risk.
New C++ programmers get confused by private virtuals because they think a
private virtual cannot be overridden. After all, a derived class cannot access
members that are private in its base class so how, they ask, could it override a
private virtual from its base class? There are explanations for the above, but
that's academic. The real issue is that almost everyone gets confused the first
time they run into private virtuals, and confusion is bad.
The rest of this FAQ gives a rationale for why C++ needs to protect you from that
danger, but before we start that, be advised that you can get the effect as if
dynamic binding worked on the this object even during a constructor via The
Dynamic Binding During Initialization Idiom.
#include <iostream>
#include <string>
class Base {
public:
Base() { println("Base::Base()"); virt(); }
virtual void virt() { println("Base::virt()"); }
};
int main()
{
Derived d;
...
}
Base::Base()
Base::virt() // ← Not Derived::virt()
Derived::Derived()
Derived::virt()
The rest of this FAQ describes why C++ does the above. If you're happy merely
knowing what C++ does without knowing why, feel free to skip this stuff.
The explanation for this behavior comes from combining two facts:
1. When you create a Derived object, it first calls Base's constructor. That's
why it prints Base::Base() before Derived::Derived().
2. While executing Base::Base(), the this object is not yet of type Derived;
its type is still merely Base. That's why the call to virtual function virt()
within Base::Base() binds to Base::virt() even though an override exists
in Derived.
Now some of you are still curious, saying to yourself, "Hmmmm, but I still wonder
why the this object is merely of type Base during Base::Base()." If that's you, the
answer is that C++ is protecting you from serious and subtle bugs. In particular, if
the above rule were different, you could easily use objects before they were
initialized, and that would cause no end of grief and havoc.
Here's how: imagine for the moment that calling this->virt() within
Base::Base() ended up invoking the override Derived::virt(). Overrides can
(and often do!) access non-static data members declared in the Derived class.
But since the non-static data members declared in Derived are not initialized
during the call to virt(), any use of them within Derived::virt() would be a
"use before initialized" error. Bang, you're dead.
So fortunately the C++ language doesn't let this happen: it makes sure any call to
this->virt() that occurs while control is flowing through Base's constructor will
end up invoking Base::virt(), not the override Derived::virt().
Yes: the Dynamic Binding During Initialization idiom (AKA Calling Virtuals During
Initialization).
class Base {
public:
Base();
...
virtual void foo(int n) const; // often pure virtual
virtual double bar() const; // often pure virtual
// if you don't want outsiders calling these, make them protected
};
Base::Base()
{
... foo(42) ... bar() ...
// these will not use dynamic binding
// goal: simulate dynamic binding in those calls
}
class Derived : public Base {
public:
...
virtual void foo(int n) const;
virtual double bar() const;
};
This FAQ shows some ways to simulate dynamic binding as if the calls made in
Base's constructor dynamically bound to the this object's derived class. The
ways we'll show have tradeoffs, so choose the one that best fits your needs, or
make up another.
class Base {
public:
void init(); // may or may not be virtual
...
virtual void foo(int n) const; // often pure virtual
virtual double bar() const; // often pure virtual
};
void Base::init()
{
... foo(42) ... bar() ...
// most of this is copied from the original Base::Base()
}
The only remaining issues are determining where to call Phase I and where to
call Phase II. There are many variations on where these calls can live; we will
consider two.
The first variation is simplest initially, though the code that actually wants to
create objects requires a tiny bit of programmer self-discipline, which in practice
means you're doomed. Seriously, if there are only one or two places that actually
create objects of this hierarchy, the programmer self-discipline is quite localized
and shouldn't cause problems.
In this variation, the code that is creating the object explicitly executes both
phases. When executing Phase I, the code creating the object either knows the
object's exact class (e.g., new Derived() or perhaps a local Derived object), or
doesn't know the object's exact class (e.g., the virtual constructor idiom or some
other factory). The "doesn't know" case is strongly preferred when you want to
make it easy to plug-in new derived classes.
Note: Phase I often, but not always, allocates the object from the heap. When it
does, you should store the pointer in some sort of managed pointer, such as a
std::auto_ptr, a reference counted pointer, or some other object whose
destructor deletes the allocation. This is the best way to prevent memory leaks
when Phase II might throw exceptions. The following example assumes Phase I
allocates the object from the heap.
#include <memory>
void joe_user()
{
std::auto_ptr<Base> p(/*...somehow create a Derived object via new...*/);
p->init();
...
}
The second variation is to combine the first two lines of the joe_user function into
some create function. That's almost always the right thing to do when there are
lots of joe_user-like functions. For example, if you're using some kind of factory,
such as a registry and the virtual constructor idiom, you could move those two
lines into a static method called Base::create():
#include <memory>
class Base {
public:
...
typedef std::auto_ptr<Base> Ptr; // typedefs simplify the code
static Ptr create();
...
};
Base::Ptr Base::create()
{
Ptr p(/*...use a factory to create a Derived object via new...*/);
p->init();
return p;
}
This simplifies all the joe_user-like functions (a little), but more importantly, it
reduces the chance that any of them will create a Derived object without also
calling init() on it.
void joe_user()
{
Base::Ptr p = Base::create();
...
}
If you're sufficiently clever and motivated, you can even eliminate the chance that
someone could create a Derived object without also calling init() on it. An
important step in achieving that goal is to make Derived's constructors, including
its copy constructor, protected or private..
The next approach does not rely on a two-phase initialization, instead using a
second hierarchy whose only job is to house methods foo() and bar(). This
approach doesn't always work, and in particular it doesn't work in cases when
foo() and bar() need to access the instance data declared in Derived, but it is
conceptually quite simple and clean and is commonly used.
Let's call the base class of this second hierarchy Helper, and its derived classes
Helper1, Helper2, etc. The first step is to move foo() and bar() into this second
hierarchy:
class Helper {
public:
virtual void foo(int n) const = 0;
virtual double bar() const = 0;
};
Next, remove init() from Base (since we're no longer using the two-phase
approach), remove foo() and bar() from Base and Derived (foo() and bar() are
now in the Helper hierarchy), and change the signature of Base's constructor so it
takes a Helper by reference:
class Base {
public:
Base(const Helper& h);
... // remove init() since not using two-phase this time
... // remove foo() and bar() since they're in Helper
};
class Derived : public Base {
public:
... // remove foo() and bar() since they're in Helper
};
Base::Base(const Helper& h)
{
... h.foo(42) ... h.bar() ...
// almost identical to the original Base::Base()
// but with h. in calls to h.foo() and h.bar()
}
Derived::Derived()
: Base(Helper2()) // ←the magic happens here
{
...
}
Note that Derived can pass values into the Helper derived class's constructor,
but it must not pass any data members that actually live inside the this object.
While we're at it, let's explicitly say that Helper::foo() and Helper::bar() must
not access data members of the this object, particularly data members declared
in Derived. (Think about when those data members are initialized and you'll see
why.)
Of course the choice of which Helper derived class could be made out in the
joe_user-like function, in which case it would be passed into the Derived ctor and
then up to the Base ctor:
Derived::Derived(const Helper& h)
: Base(h)
{
...
}
If the Helper objects don't need to hold any data, that is, if each is merely a
collection of its methods, then you can simply pass static member functions
instead. This might be simpler since it entirely eliminates the Helper hierarchy.
class Base {
public:
typedef void (*FooFn)(int); // typedefs simplify
typedef double (*BarFn)(); // the rest of the code
Base(FooFn foo, BarFn bar);
...
};
Derived::Derived()
: Base(foo, bar) // ←pass the function-ptrs into Base's ctor
{
...
}
As before, the functionality for foo() and/or bar() can be passed in from the
joe_user-like functions. In that case, Derived's ctor just accepts them and passes
them up into Base's ctor:
A final approach is to use templates to "pass" the functionality into the derived
classes. This is similar to the case where the joe_user-like functions choose the
initializer-function or the Helper derived class, but instead of using function
pointers or dynamic binding, it wires the code into the classes via templates.
[23.7] I'm getting the same mess with destructors: calling a virtual
on my this object from my base class's destructor ends up
ignoring the override in the derived class; what's going on?
C++ is protecting you from yourself. What you are trying to do is very dangerous,
and if the compiler did what you wanted, you'd be in worse shape.
For rationale of why C++ needs to protect you from that danger, read FAQ [23.5].
The situation during a destructor is analogous to that during the constructor. In
particular, within the {body} of Base::~Base(), an object that was originally of
type Derived has already been demoted (devolved, if you will) to an object of
type Base. If you call a virtual function that has been overridden in class Derived,
the call will resolve to Base::virt(), not to the override Derived::virt(). Same
goes for using typeid on the this object: the this object really has been
demoted to type Base; it is no longer an object of type Derived.
Here's the mess you're in: if Base declares a member function f(double x), and
Derived declares a member function f(char c) (same name but different
parameter types and/or constness), then the Base f(double x) is "hidden" rather
than "overloaded" or "overridden" (even if the Base f(double x) is virtual).
class Base {
public:
void f(double x); ← doesn't matter whether or not this is virtual
};
class Derived : public Base {
public:
void f(char c); ← doesn't matter whether or not this is virtual
};
int main()
{
Derived* d = new Derived();
Base* b = d;
b->f(65.3); ← okay: passes 65.3 to f(double x)
d->f(65.3); ← bizarre: converts 65.3 to a char ('A' if ASCII) and passes it to f(
char c); does NOT call f(double x)!!
return 0;
}
Here's how you get out of the mess: Derived must have a using declaration of
the hidden member function. For example,
class Base {
public:
void f(double x);
};
If the using syntax isn't supported by your compiler, redefine the hidden Base
member function(s), even if they are non-virtual. Normally this re-definition
merely calls the hidden Base member function using the :: syntax. E.g.,
Note: the hiding problem also occurs if class Base declares a method f(char).
Note: warnings are not part of the standard, so your compiler may or may not
give the above warning.
Note: nothing gets hidden when you have a base-pointer. Think about it: what a
derived class does or does not do is irrelevant when the compiler is dealing with
a base-pointer. The compiler might not even know that the particular derived
class exists. Even if it knows of the existence some particular derived class, it
cannot assume that a specific base-pointer necessarily points at an object of that
particular derived class. Hiding takes place when you have a derived pointer, not
when you have a base pointer.
If you get a link error of the form "Error: Unresolved or undefined symbols
detected: virtual table for class Fred," you probably have an undefined
virtual member function in class Fred.
The compiler typically creates a magical data structure called the "virtual table"
for classes that have virtual functions (this is how it handles dynamic binding).
Normally you don't have to know about it at all. But if you forget to define a
virtual function for class Fred, you will sometimes get this linker error.
Here's the nitty gritty: Many compilers put this magical "virtual table" in the
compilation unit that defines the first non-inline virtual function in the class.
Thus if the first non-inline virtual function in Fred is wilma(), the compiler will
put Fred's virtual table in the same compilation unit where it sees Fred::wilma().
Unfortunately if you accidentally forget to define Fred::wilma(), rather than
getting a Fred::wilma() is undefined, you may get a "Fred's virtual table is
undefined". Sad but true.
This is known as making the class "final" or "a leaf." There are three ways to do
it: an easy technical approach, an even easier non-technical approach, and a
slightly trickier technical approach.
The (easy) technical approach is to make the class's constructors private and
to use the Named Constructor Idiom to create the objects. No one can create
objects of a derived class since the base class's constructor will be inaccessible.
The "named constructors" themselves could return by pointer if you want your
objects allocated by new or they could return by value if you want the objects
created on the stack.
The (even easier) non-technical approach is to put a big fat ugly comment
next to the class definition. The comment could say, for example, // We'll fire
you if you inherit from this class or even just /*final*/ class Whatever
{...};.Some programmers balk at this because it is enforced by people rather
than by technology, but don't knock it on face value: it is quite effective in
practice.
class Fred;
class FredBase {
private:
friend class Fred;
FredBase() { }
};
Class Fred can access FredBase's ctor, since Fred is a friend of FredBase, but no
class derived from Fred can access FredBase's ctor, and therefore no one can
create a concrete class derived from Fred.
This is known as making the method "final" or "a leaf." Here's an easy-to-use
solution to this that gives you 90+% of what you want: simply add a comment
next to the method and rely on code reviews or random maintenance activities to
find violators. The comment could say, for example, // We'll fire you if you
override this method or perhaps more likely, /*final*/ void theMethod();.
In any case, this solution should give you most of the potential benefit at almost
no cost.
E.g., the "Car has-a Engine" relationship can be expressed using simple
composition:
class Engine {
public:
Engine(int numCylinders);
void start(); // Starts this Engine
};
class Car {
public:
Car() : e_(8) { } // Initializes this Car with 8 cylinders
void start() { e_.start(); } // Start this Car by starting its Engine
private:
Engine e_; // Car has-a Engine
};
The "Car has-a Engine" relationship can also be expressed using private
inheritance:
Note that private inheritance is usually used to gain access into the protected
members of the base class, but this is usually a short-term solution (translation: a
band-aid).
Use composition when you can, private inheritance when you have to.
Normally you don't want to have access to the internals of too many other
classes, and private inheritance gives you some of this extra power (and
responsibility). But private inheritance isn't evil; it's just more expensive to
maintain, since it increases the probability that someone will change something
that will break your code.
A legitimate, long-term use for private inheritance is when you want to build a
class Fred that uses code in a class Wilma, and the code from class Wilma
needs to invoke member functions from your new class, Fred. In this case, Fred
calls non-virtuals in Wilma, and Wilma calls (usually pure virtuals) in itself, which
are overridden by Fred. This would be much harder to do with composition.
class Wilma {
protected:
void fredCallsWilma()
{
std::cout << "Wilma::fredCallsWilma()\n";
wilmaCallsFred();
}
virtual void wilmaCallsFred() = 0; // A pure virtual function
};
class Fred : private Wilma {
public:
void barney()
{
std::cout << "Fred::barney()\n";
Wilma::fredCallsWilma();
}
protected:
virtual void wilmaCallsFred()
{
std::cout << "Fred::wilmaCallsFred()\n";
}
};
Generally, No.
[24.6] What are the access rules with private and protected
inheritance?
class B { /*...*/ };
class D_priv : private B { /*...*/ };
class D_prot : protected B { /*...*/ };
class D_publ : public B { /*...*/ };
class UserClass { B b; /*...*/ };
None of the derived classes can access anything that is private in B. In D_priv,
the public and protected parts of B are private. In D_prot, the public and
protected parts of B are protected. In D_publ, the public parts of B are public
and the protected parts of B are protected (D_publ is-a-kind-of-a B). class
UserClass can access only the public parts of B, which "seals off" UserClass
from B.
Please make sure you understand the high-level / strategy / design issues. Too
many programmers worry about getting "it" to compile without first deciding
whether they really want "it" in the first place. So please read the first several
FAQs in this section before worrying about the (important) mechanical details in
the last several FAQs.
Grrrrrrrrr.
It really bothers me when people think they know what's best for your problem
even though they've never seen your problem!! How can anybody possibly know
that multiple inheritance won't help you accomplish your goals without knowing
your goals?!?!?!?!!!
Next time somebody tells you that you should never use multiple inheritance,
look them straight in the eye and say, "One size does not fit all." If they respond
with something about their bad experience on their project, look them in the eye
and repeat, slower this time, "One size does not fit all."
People who spout off one-size-fits-all rules presume to make your design
decisions without knowing your requirements. They don't know where you're
going but know how you should get there.
Don't trust an answer from someone who doesn't know the question.
You won't use it all the time. You might not even use it regularly. But there are
some situations where a solution with multiple inheritance is cheaper to build,
debug, test, optimize, and maintain than a solution without multiple inheritance. If
multiple inheritance cuts your costs, improves your schedule, reduces your risk,
and performs well, then please use it.
On the other hand, just because it's there doesn't mean you should use it. Like
any tool, use the right tool for the job. If MI (multiple inheritance) helps, use it; if
not, don't. And if you have a bad experience with it, don't blame the tool. Take
responsibility for your mistakes, and say, "I used the wrong tool for the job; it was
my fault." Do not say, "Since it didn't help my problem, it's bad for all problems in
all industries across all time." Good workmen never blame their tools.
M.I. rule of thumb #2: Try especially hard to use ABCs when you use MI. In
particular, most classes above the join class (and often the join class itself)
should be ABCs. In this context, "ABC" doesn't simply mean "a class with at least
one pure virtual function"; it actually means a pure ABC, meaning a class with as
little data as possible (often none), and with most (often all) its methods being
pure virtual. Rationale: this discipline helps you avoid situations where you need
to inherit data or code along two paths, plus it encourages you to use inheritance
properly. This second goal is subtle but is extremely powerful. In particular, if
you're in the habit of using inheritance for code reuse (dubious at best; see
above), this rule of thumb will steer you away from MI and perhaps (hopefully!)
away from inheritance-for-code-reuse in the first place. In other words, this rule of
thumb tends to push people toward inheritance-for-interface-substitutability,
which is always safe, and away from inheritance-just-to-help-me-write-less-code-
in-my-derived-class, which is often (not always) unsafe.
M.I. rule of thumb #3: Consider the "bridge" pattern or nested generalization as
possible alternatives to multiple inheritance. This does not imply that there is
something "wrong" with MI; it simply implies that there are at least three
alternatives, and a wise designer checks out all the alternatives before choosing
which is best.
Suppose you have land vehicles, water vehicles, air vehicles, and space
vehicles. (Forget the whole concept of amphibious vehicles for this example;
pretend they don't exist for this illustration.) Suppose we also have different
power sources: gas powered, wind powered, nuclear powered, pedal powered,
etc. We could use multiple inheritance to tie everything together, but before we
do, we should ask a few tough questions:
1. Will the users of LandVehicle need to have a Vehicle& that refers to a
LandVehicle object? In particular, will the users call methods on a
Vehicle-reference and expect the actual implementation of those methods
to be specific to LandVehicles?
2. Ditto for GasPoweredVehicles: will the users want a Vehicle reference that
refers to a GasPoweredVehicle object, and in particular will they want to
call methods on that Vehicle reference and expect the implementations to
get overridden by GasPoweredVehicle?
If both answers are "yes," multiple inheritance is probably the best way to go. But
before you close the door on the alternatives, here are a few more "decision
criteria." Suppose there are N geographies (land, water, air, space, etc.) and M
power sources (gas, nuclear, wind, pedal, etc.). There are at least three choices
for the overall design: the bridge pattern, nested generalization, and multiple
inheritance. Each has its pros/cons:
• With the bridge pattern, you create two distinct hierarchies: ABC Vehicle
has derived classes LandVehicle, WaterVehicle, etc., and ABC Engine
has derived classes GasPowered, NuclearPowered, etc. Then the Vehicle
has an Engine* (that is, an Engine-pointer), and users mix and match
vehicles and engines at run-time. This has the advantage that you only
have to write N+M derived classes, which means things grow very
gracefully: when you add a new geography (incrementing N) or engine
type (incrementing M), you need add only one new derived class.
However you have several disadvantages as well: you only have N+M
derived classes which means you only have at most N+M overrides and
therefore N+M concrete algorithms / data structures. If you ultimately want
different algorithms and/or data structures in the N*M combinations, you'll
have to work hard to make that happen, and you're probably better off with
something other than a pure bridge pattern. The other thing the bridge
doesn't solve for you is eliminating the nonsensical choices, such as pedal
powered space vehicles. You can solve that by adding extra checks when
the users combine vehicles and engines at run-time, but it requires a bit of
skullduggery, something the bridge pattern doesn't provide for free. The
bridge also restricts users since, although there is a common base class
above all geographies (meaning a user can pass any kind of vehicle as a
Vehicle&), there is not a common base class above, for example, all gas
powered vehicles, and therefore users cannot pass any gas powered
vehicle as a GasPoweredVehicle&. Finally, the bridge has the advantage
that it shares code between the group of, for example, water vehicles as
well as the group of, for example, gas powered vehicles. In other words,
the various gas powered vehicles share the code in derived class
GasPoweredEngine.
• With nested generalization, you pick one of the hierarchies as primary
and the other as secondary, and you have a nested hierarchy. For
example, if you choose geography as primary, Vehicle would have
derived classes LandVehicle, WaterVehicle, etc., and those would each
have further derived classes, one per power source type. E.g.,
LandVehicle would have derived classes GasPoweredLandVehicle,
PedalPoweredLandVehicle, NuclearPoweredLandVehicle, etc.;
WaterVehicle would have a similar set of derived classes, etc. This
requires you to write roughly N*M different derived classes, which means
things don't grow gracefully when you increment N or M, but it gives you
the advantage over the bridge that you can have N*M different algorithms
and data structures. It also gives you fine granular control, since the user
cannot select nonsensical combinations, such as pedal powered space
vehicles, since the user can select only those combinations that a
programmer has decided are reasonable. Unfortunately nested
generalization doesn't improve the problem with passing any gas powered
vehicle as a common base class, since there is no common base class
above the secondary hierarchy, e.g., there is no GasPoweredVehicle base
class. And finally, it's not obvious how to share code between all vehicles
that use the same power source, e.g., between all gas powered vehicles.
• With multiple inheritance, you have two distinct hierarchies, just like the
bridge, but you remove the Engine* from the bridge and instead create
roughly N*M derived classes below both the hierarchy of geographies and
the hierarchy of power sources. It's not as simple as this, since you'll need
to change the concept of the Engine classes. In particular, you'll want to
rename the classes in that hierarchy from, for example, GasPoweredEngine
to GasPoweredVehicle; plus you'll need to make corresponding changes to
the methods in the hierarchy. In any case, class GasPoweredLandVehicle
will multiply inherit from GasPoweredVehicle and LandVehicle, and similarly
with GasPoweredWaterVehicle, NuclearPoweredWaterVehicle, etc. Like
nested generalization, you have to write roughly N*M classes, which
doesn't grow gracefully, but it does give you fine granular control over both
which algorithm and data structures to use in the various derived classes
as well as which combinations are deemed "reasonable," meaning you
simply don't create nonsensical choices like PedalPoweredSpaceVehicle. It
solves a problem shared by both bridge and nested generalization,
namely it allows a user to pass any gas powered vehicle using a common
base class. Finally it provides a solution to the code-sharing problem, a
solution that is at least as good as that of the bridge solution: it lets all gas
powered vehicles share common code when that is desired. We say this is
"at least as good as the solution from the bridge" since, unlike the bridge,
the derived classes can share common code within gas powered vehicles,
but can also, unlike with the bridge, override and replace that code in
cases where the shared code is not ideal.
The most important point: there is no universally "best" answer. Perhaps you
were hoping I would tell you to always use one or the other of the above choices.
I'd be happy to do that except for one minor detail: it'd be a lie. If exactly one of
the above was always best, then one size would fit all, and we know it does not.
So here's what you have to do: T H I N K. You'll have to make a decision. I'll give
you some guidelines, but ultimately you will have to decide what is best (or
perhaps "least bad") for your situation.
Nested Multiple
Bridge
generalization inheritance
Does it grow gracefully when adding
geography or power source?
How much code needs to be (N+M
written? (N*M chunks) (N*M chunks)
chunks)
Do you have fine granular control
over the algorithms and data
structures?
Do you have fine granular control
over nonsensical combinations?
Does it let users treat either base
class polymorphically?
Does it let derived classes share
common code from either side?
Warning: the reader should not be naive in using the above matrix. For example,
do not simply add up the number of and marks, then decide based on which
design has the most good and least bad. The first step in using the above matrix
is to find out if there are additional design approaches, that is, additional
columns. And don't forget: the bridge and nested generalization columns are
really both pairs of columns, since in both cases there is an asymmetry that could
go in either direction. In other words, one could put an Engine* in Vehicle or a
Vehicle* in Engine (or both, or some other way to pair them up, such as a small
object that contains just a Vehicle* and an Engine*). Similarly, with nested
generalization you could decompose first by geography (land, water, etc.) or first
by power source (gas, nuclear, etc.), yielding two distinct designs with distinct
tradeoffs.
The second step in using the above matrix is to give a "weight" to each row. For
example, in your particular situation, the amount of code that must get written
(second row) may be more or less important than the granular control over data
structures. The ultimate decision will be made by finding out which approach is
best for your situation. One size does not fit all — do not expect the answer in
one project to be the same as the answer in another project.
This second example is only slightly different from the previous since it is more
obviously symmetric. This symmetry tilts the scales slightly toward the multiple
inheritance solution, but one of the others still might be best in some situations.
In this example, we have only two categories of vehicles: land vehicles and water
vehicles. Then somebody points out that we need amphibious vehicles. Now we
get to the good part: the questions.
If we get three "yes" answers, multiple inheritance is probably the right choice. To
be sure, you should ask the other questions as well, e.g., the grow-gracefully
issue, the granularity of control issues, etc.
class Base {
public:
...
protected:
int data_;
};
int main()
{
Join* j = new Join();
Base* b = j; ← bad: this is ambiguous; see below
}
Forgive the ASCII-art, but the inheritance hierarchy looks something like this:
Base
/ \
/ \
/ \
Der1 Der2
\ /
\ /
\ /
Join
The key is to realize that Base is inherited twice, which means any data members
declared in Base, such as data_ above, will appear twice within a Join object.
This can create ambiguities: which data_ did you want to change? For the same
reason the conversion from Join* to Base*, or from Join& to Base&, is ambiguous:
which Base class subobject did you want?
C++ lets you resolve the ambiguities. For example, instead of saying data_ = 1
you could say Der2::data_ = 1, or you could convert from Join* to a Der1* and
then to a Base*. However please, Please, PLEASE think before you do that. That
is almost always not the best solution. The best solution is typically to tell the C+
+ compiler that only one Base subobject should appear within a Join object, and
that is described next.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
To avoid the duplicated base class subobject that occurs with the "dreaded
diamond", you should use the virtual keyword in the inheritance part of the
classes that derive directly from the top of the diamond:
class Base {
public:
...
protected:
int data_;
};
int main()
{
Join* j = new Join();
Base* b = j; ← good: this is now unambiguous
}
Because of the virtual keyword in the base-class portion of Der1 and Der2, an
instance of Join will have have only a single Base subobject. This eliminates the
ambiguities. This is usually better than using full qualification as described in the
previous FAQ.
For emphasis, the virtual keyword goes in the hierarchy above Der1 and Der2. It
doesn't help to put the virtual keyword in the Join class itself. In other words,
you have to know that a join class will exist when you are creating class Der1 and
Der2.
Base
/ \
/ \
virtual / \ virtual
Der1 Der2
\ /
\ /
\ /
Join
class Base {
public:
virtual void foo() = 0;
virtual void bar() = 0;
};
void Der1::foo()
{ bar(); }
int main()
{
Join* p1 = new Join();
Der1* p2 = p1;
Base* p3 = p1;
p1->foo();
p2->foo();
p3->foo();
}
Believe it or not, when Der1::foo() calls this->bar(), it ends up calling
Der2::bar(). Yes, that's right: a class that Der1 knows nothing about will supply
the override of a virtual function invoked by Der1::foo(). This "cross delegation"
can be a powerful technique for customizing the behavior of polymorphic classes.
Generally, virtual base classes are most suitable when the classes that derive
from the virtual base, and especially the virtual base itself, are pure abstract
classes. This means the classes above the "join class" have very little if any data.
Note: even if the virtual base itself is a pure abstract class with no member data,
you still probably don't want to remove the virtual inheritance within classes Der1
and Der2. You can use fully qualified names to resolve any ambiguities that arise,
and you might even be able to squeeze out a few cycles in some cases, however
the object's address is somewhat ambiguous (there are still two Base class
subobjects in the Join object), so simple things like trying to find out if two
pointers point at the same instance might be tricky. Just be careful — very
careful.
Because a virtual base class subobject occurs only once in an instance, there
are special rules to make sure the virtual base class's constructor and destructor
get called exactly once per instance. The C++ rules say that virtual base classes
are constructed before all non-virtual base classes. The thing you as a
programmer need to know is this: constructors for virtual base classes anywhere
in your class's inheritance hierarchy are called by the "most derived" class's
constructor.
Practically speaking, this means that when you create a concrete class that has a
virtual base class, you must be prepared to pass whatever parameters are
required to call the virtual base class's constructor. And, of course, if there are
several virtual base classes anywhere in your classes ancestry, you must be
prepared to call all their constructors. This might mean that the most-derived
class's constructor needs more parameters than you might otherwise think.
However, if the author of the virtual base class followed the guideline in the
previous FAQ, then the virtual base class's constructor probably takes no
parameters since it doesn't have any data to initialize. This means (fortunately!)
the authors of the concrete classes that inherit eventually from the virtual base
class do not need to worry about taking extra parameters to pass to the virtual
base class's ctor.
(Rest to be written.)
The very first constructors to be executed are the virtual base classes anywhere
in the hierarchy. They are executed in the order they appear in a depth-first left-
to-right traversal of the graph of base classes, where left to right refer to the order
of appearance of base class names.
After all virtual base class constructors are finished, the construction order is
generally from base class to derived class. The details are easiest to understand
if you imagine that the very first thing the compiler does in the derived class's ctor
is to make a hidden call to the ctors of its non-virtual base classes (hint: that's the
way many compilers actually do it). So if class D inherits multiply from B1 and
B2, the constructor for B1 executes first, then the constructor for B2, then the
constructor for D. This rule is applied recursively; for example, if B1 inherits from
B1a and B1b, and B2 inherits from B2a and B2b, then the final order is B1a, B1b,
B1, B2a, B2b, B2, D.
Note that the order B1 and then B2 (or B1a then B1b) is determined by the order
that the base classes appear in the declaration of the class, not in the order that
the initializer appears in the derived class's initialization list.
Long answer: suppose the "most derived" class is D, meaning the actual object
that was originally created was of class D, and that D inherits multiply (and non-
virtually) from B1 and B2. The sub-object corresponding to most-derived class D
runs first, followed by the dtors for its non-virtual base classes in reverse
declaration-order. Thus the destructor order will be D, B2, B1. This rule is applied
recursively; for example, if B1 inherits from B1a and B1b, and B2 inherits from
B2a and B2b, the final order is D, B2, B2b, B2a, B1, B1b, B1a.
After all this is finished, virtual base classes that appear anywhere in the
hierarchy are handled. The destructors for these virtual base classes are
executed in the reverse order they appear in a depth-first left-to-right traversal of
the graph of base classes, where left to right refer to the order of appearance of
base class names. For instance, if the virtual base classes in that traversal order
are V1, V1, V1, V2, V1, V2, V2, V1, V3, V1, V2, the unique ones are V1, V2, V3,
and the final-final order is D, B2, B2b, B2a, B1, B1b, B1a, V3, V2, V1.
Reminder to make your base class's destructor virtual, at least in the normal
case. If you don't thoroughly understand the rules for why you make your base
class's destructor virtual, then either learn the rationale or just trust me and make
them virtual.
Look, I know this is going to hurt your head, so please, please just read the next
few FAQs in sequence and hopefully the pain will go away by sometime next
week.
Bytes.
For example, if sizeof(Fred) is 8, the distance between two Fred objects in an
array of Freds will be exactly 8 bytes.
As another example, this means sizeof(char) is one byte. That's right: one byte.
One, one, one, exactly one byte, always one byte. Never two bytes. No
exceptions.
I'm really sorry if that hurts, but believe me, it's better to get all the pain over with
at once. Take a deep breath and repeat after me: "character and char might be
different." There, doesn't that feel better? No? Well keep reading — it gets worse.
[26.4] But, but, but what about machines where a char has more
than 8 bits? Surely you're not saying a C++ byte might have
more than 8 bits, are you?!?
Yep, that's right: a C++ byte might have more than 8 bits.
The C++ language guarantees a byte must always have at least 8 bits. But there
are implementations of C++ that have more than 8 bits per byte.
[26.5] Okay, I could imagine a machine with 9-bit bytes. But surely
not 16-bit bytes or 32-bit bytes, right?
Wrong.
I have heard of one implementation of C++ that has 64-bit "bytes." You read that
right: a byte on that implementation has 64 bits. 64 bits per byte. 64. As in 8
times 8.
And yes, you're right, combining with the above would mean that a char on that
implementation would have 64 bits.
[26.6] I'm sooooo confused. Would you please go over the rules
about bytes, chars, and characters one more time?
• The C++ language gives the programmer the impression that memory is
laid out as a sequence of something C++ calls "bytes."
• Each of these things that the C++ language calls a byte has at least 8 bits,
but might have more than 8 bits.
• The C++ language guarantees that a char* (char pointers) can address
individual bytes.
• The C++ language guarantees there are no bits between two bytes. This
means every bit in memory is part of a byte. If you grind your way through
memory via a char*, you will be able to see every bit.
• The C++ language guarantees there are no bits that are part of two
distinct bytes. This means a change to one byte will never cause a change
to a different byte.
• The C++ language gives you a way to find out how many bits are in a byte
in your particular implementation: include the header <climits>, then the
actual number of bits per byte will be given by the CHAR_BIT macro.
Let's work an example to illustrate these rules. The PDP-10 has 36-bit words with
no hardware facility to address anything within one of those words. That means a
pointer can point only at things on a 36-bit boundary: it is not possible for a
pointer to point 8 bits to the right of where some other pointer points.
One way to abide by all the above rules is for a PDP-10 C++ compiler to define a
"byte" as 36 bits. Another valid approach would be to define a "byte" as 9 bits,
and simulate a char* by two words of memory: the first could point to the 36-bit
word, the second could be a bit-offset within that word. In that case, the C++
compiler would need to add extra instructions when compiling code using char*
pointers. For example, the code generated for *p = 'x' might read the word into
a register, then use bit-masks and bit-shifts to change the appropriate 9-bit byte
within that word. An int* could still be implemented as a single hardware pointer,
since C++ allows sizeof(char*) != sizeof(int*).
Using the same logic, it would also be possible to define a PDP-10 C++ "byte" as
12-bits or 18-bits. However the above technique wouldn't allow us to define a
PDP-10 C++ "byte" as 8-bits, since 8*4 is 32, meaning every 4th byte we would
skip 4 bits. A more complicated approach could be used for those 4 bits, e.g., by
packing nine bytes (of 8-bits each) into two adjacent 36-bit words. The important
point here is that memcpy() has to be able to see every bit of memory: there can't
be any bits between two adjacent bytes.
Note: one of the popular non-C/C++ approaches on the PDP-10 was to pack 5
bytes (of 7-bits each) into each 36-bit word. However this won't work in C or C++
since 5*7 = 35, meaning using char*s to walk through memory would "skip" a bit
every fifth byte (and also because C++ requires bytes to have at least 8 bits).
A POD type is a C++ type that has an equivalent in C, and that uses the same
rules as C uses for initialization, copying, layout, and addressing.
The actual definition of a POD type is recursive and gets a little gnarly. Here's a
slightly simplified definition of POD: a POD type's non-static data members must
be public and can be of any of these types: bool, any numeric type including the
various char variants, any enumeration type, any data-pointer type (that is, any
type convertible to void*), any pointer-to-function type, or any POD type,
including arrays of any of these. Note: data-pointers and pointers-to-function are
okay, but pointers-to-member are not. Also note that references are not allowed.
In addition, a POD type can't have constructors, virtual functions, base classes,
or an overloaded assignment operator.
No, the C++ language requires that your operator overloads take at least one
operand of a "class type" or enumeration type. The C++ language will not let you
define an operator all of whose operands / parameters are of primitive types.
For example, you can't define an operator== that takes two char*s and uses
string comparison. That's good news because if s1 and s2 are of type char*, the
expression s1 == s2 already has a well defined meaning: it compares the two
pointers, not the two strings pointed to by those pointers. You shouldn't use
pointers anyway. Use std::string instead of char*.
If C++ let you redefine the meaning of operators on built-in types, you wouldn't
ever know what 1 + 1 is: it would depend on which headers got included and
whether one of those headers redefined addition to mean, for example,
subtraction.
So here's the rule: if a points to an array of thingies that was allocated via new
T[n], then you must, must, must delete it via delete[] a. Even if the elements in
the array are built-in types. Even if they're of type char or int or void*. Even if
you don't understand why.
Thank you for reading this answer rather than just trying to set your own coding
standards.
But beware that some people on comp.lang.c++ are very sensitive on this issue.
Nearly every software engineer has, at some point, been exploited by someone
who used coding standards as a "power play." Furthermore some attempts to set
C++ coding standards have been made by those who didn't know what they were
talking about, so the standards end up being based on what was the state-of-the-
art when the standards setters were writing code. Such impositions generate an
attitude of mistrust for coding standards.
Obviously anyone who asks this question wants to be trained so they don't run
off on their own ignorance, but nonetheless posting a question such as this one
to comp.lang.c++ tends to generate more heat than light.
For an excellent book on the subject, get Sutter and Alexandrescu, C++ Coding
Standards, 220 pgs, Addison-Wesley, 2005, ISBN 0-321-11358-6. It provides
101 rules, guidelines and best practices. The authors and editors produced some
solid material, then did an unusually good job of energizing the peer-review team.
All of this improved the book. Buy it.
But you really want more than a coding standard. The structure provided by
coding standards gives neophytes one less degree of freedom to worry about,
which is good. However, pragmatic guidelines should go well beyond pretty-
printing standards. Organizations need a consistent philosophy of design and
implementation. E.g., strong or weak typing? references or pointers in interfaces?
stream I/O or stdio? should C++ code call C code? vice versa? how should ABCs
be used? should inheritance be used as an implementation technique or as a
specification technique? what testing strategy should be employed? inspection
strategy? should interfaces uniformly have a get() and/or set() member function
for each data member? should interfaces be designed from the outside-in or the
inside-out? should errors be handled by try/catch/throw or by return codes? etc.
Few argue that coding standards are "ideal," or even "good," however they are
necessary in the kind of organizations/situations described above.
The following FAQs provide some basic guidance in conventions and styles.
No!
One more thing: whenever something is in demand, the potential for charlatans
increases. Look before you leap. Also ask for student-reviews from past
companies, since not even expertise makes someone a good communicator.
Finally, select a practitioner who can teach, not a full time teacher who has a
passing knowledge of the language/paradigm.
The headers in ISO Standard C++ don't have a .h suffix. This is something the
standards committee changed from former practice. The details are different
between headers that existed in C and those that are specific to C++.
The C++ standard library is guaranteed to have 18 standard headers from the C
language. These headers come in two standard flavors, <cxxx> and <xxx.h>
(where xxx is the basename of the header, such as stdio, stdlib, etc). These
two flavors are identical except the <cxxx> versions provide their declarations in
the std namespace only, and the <xxx.h> versions make them available both in
std namespace and in the global namespace. The committee did it this way so
that existing C code could continue to be compiled in C++. However the <xxx.h>
versions are deprecated, meaning they are standard now but might not be part of
the standard in future revisions. (See clause D.5 of the ISO C++ standard.)
For new projects, use only the <xxx> headers, not the <xxx.h> headers.
When modifying or extending existing code that uses the old header names, you
should probably follow the practice in that code unless there's some important
reason to switch to the standard headers (such as a facility available in standard
<iostream> that was not available in the vendor's <iostream.h>). If you need to
standardize existing code, make sure to change all C++ headers in all program
units including external libraries that get linked in to the final executable.
All of this affects the standard headers only. You're free to name your own
headers anything you like; see [27.9].
Probably not.
People don't like typing std:: over and over, and they discover that using
namespace std lets the compiler see any std name, even if unqualified. The fly in
that ointment is that it lets the compiler see any std name, even the ones you
didn't think about. In other words, it can create name conflicts and ambiguities.
For example, suppose your code is counting things and you happen to use a
variable or function named count. But the std library also uses the name count
(it's one of the std algorithms), which could cause ambiguities.
If you really want to avoid typing std::, then you can either use something else
called a using-declaration, or get over it and just type std:: (the un-solution):
I personally find it's faster to type "std::" than to decide, for each distinct std
name, whether or not to include a using-declaration and if so, to find the best
scope and add it there. But either way is fine. Just remember that you are part of
a team, so make sure you use an approach that is consistent with the rest of your
organization.
No, but as always, remember that readability is one of the most important things.
Some people feel the ?: ternary operator should be avoided because they find it
confusing at times compared to the good old if statement. In many cases ?:
tends to make your code more difficult to read (and therefore you should replace
those usages of ?: with if statements), but there are times when the ?: operator
is clearer since it can emphasize what's really happening, rather than the fact
that there's an if in there somewhere.
Let's start with a really simple case. Suppose you need to print the result of a
function call. In that case you should put the real goal (printing) at the beginning
of the line, and bury the function call within the line since it's relatively incidental
(this left-right thing is based on the intuitive notion that most developers think the
first thing on a line is the most important thing):
Now let's extend this idea to the ?: operator. Suppose your real goal is to print
something, but you need to do some incidental decision logic to figure out what
should be printed. Since the printing is the most important thing conceptually, we
prefer to put it first on the line, and we prefer to bury the incidental decision logic.
In the example code below, variable n represents the number of senders of a
message; the message itself is being printed to std::cout:
All that being said, you can get pretty outrageous and unreadable code ("write
only code") using various combinations of ?:, &&, ||, etc. For example,
Personally I think the explicit if example is clearer since it emphasizes the major
thing that's going on (a decision based on the result of calling f()) rather than the
minor thing (calling f()). In other words, the use of if here is good for precisely
the same reason that it was bad above: we want to major on the majors and
minor on the minors.
In any event, don't forget that readability is the goal (at least it's one of the goals).
Your goal should not be to avoid certain syntactic constructs such as ?: or && or
|| or if — or even goto. If you sink to the level of a "Standards Bigot," you'll
ultimately embarass yourself since there are always counterexamples to any
syntax-based rule. If on the other hand you emphasize broad goals and
guidelines (e.g., "major on the majors," or "put the most important thing first on
the line," or even "make sure your code is obvious and readable"), you're usually
much better off.
Code must be written to be read, not by the compiler, but by another human
being.
A common retort to the above is: "we'll provide set() member functions for every
datum in our objects so the cost of construction will be spread out." This is worse
than the performance overhead, since now you're introducing a maintenance
nightmare. Providing a set() member function for every datum is tantamount to
public data: you've exposed your implementation technique to the world. The
only thing you've hidden is the physical names of your member objects, but the
fact that you're using a List and a String and a float, for example, is open for
all to see.
Bottom line: Locals should be declared near their first use. Sorry that this isn't
familiar to C experts, but new doesn't necessarily mean bad.
If you already have a convention, use it. If not, consult your compiler to see what
the compiler expects. Typical answers are: .cpp, .C, .cc, or .cxx (naturally the .C
extension assumes a case-sensitive file system to distinguish .C from .c).
We've often used .cpp for our C++ source files, and we have also used .C. In the
latter case, when porting to case-insensitive file systems you need to tell the
compiler to treat .c files as if they were C++ source files (e.g., -Tdp for IBM
CSet++, -cpp for Zortech C++, -P for Borland C++, etc.).
The point is that none of these filename extensions are uniformly superior to the
others. We generally use whichever technique is preferred by our customer
(again, these issues are dominated by business considerations, not by technical
considerations).
If you already have a convention, use it. If not, and if you don't need your editor
to distinguish between C and C++ files, simply use .h. Otherwise use whatever
the editor wants, such as .H, .hh, or .hpp.
We've tended to use either .h or .hpp for our C++ header files.
Yes, there are some practices which are generally considered dangerous.
However none of these are universally "bad," since situations arise when even
the worst of these is needed:
This way the "constructive" binary operators don't even need to be friends.
But it is sometimes possible to more efficiently implement common
operations (e.g., if class Fred is actually std::string, and += has to
reallocate/copy string memory, it may be better to know the eventual
length from the beginning).
Because they're evil! (Which means you should use them sparingly and with
great care.)
For some reason, programmers are sloppy in their use of pointer casts. They
cast this to that all over the place, then they wonder why things don't quite work
right. Here's the worst thing: when the compiler gives them an error message,
they add a cast to "shut the compiler up," then they "test it" to see if it seems to
work. If you have a lot of pointer casts or reference casts, read on.
The compiler will often be silent when you're doing pointer-casts and/or reference
casts. Pointer-casts (and reference-casts) tend to shut the compiler up. I think of
them as a filter on error messages: the compiler wants to complain because it
sees you're doing something stupid, but it also sees that it's not allowed to
complain due to your pointer-cast, so it drops the error message into the bit-
bucket. It's like putting duct tape on the compiler's mouth: it's trying to tell you
something important, but you've intentionally shut it up.
A pointer-cast says to the compiler, "Stop thinking and start generating code; I'm
smart, you're dumb; I'm big, you're little; I know what I'm doing so just pretend
this is assembly language and generate the code." The compiler pretty much
blindly generates code when you start casting — you are taking control (and
responsibility!) for the outcome. The compiler and the language reduce (and in
some cases eliminate!) the guarantees you get as to what will happen. You're on
your own.
By way of analogy, even if it's legal to juggle chainsaws, it's stupid. If something
goes wrong, don't bother complaining to the chainsaw manufacturer — you did
something they didn't guarantee would work. You're on your own.
(To be completely fair, the language does give you some guarantees when you
cast, at least in a limited subset of casts. For example, it's guaranteed to work as
you'd expect if the cast happens to be from an object-pointer (a pointer to a piece
of data, as opposed to a pointer-to-function or pointer-to-member) to type void*
and back to the same type of object-pointer. But in a lot of cases you're on your
own.)
One more thing: don't import a coding style onto platform-specific code where it
is foreign. For example, a coding style that seems natural while using a Microsoft
library might look bizarre and random while using a UNIX library. Don't do it.
Allow different styles for different platforms. (Just in case someone out there isn't
reading carefully, don't send me email about the case of common code that is
designed to be used/ported to several platforms, since that code wouldn't be
platform-specific, so the above "allow different styles" guideline doesn't even
apply.)
Okay, one more. Really. Don't fight the coding styles used by automatically
generated code (e.g., by tools that generate code). Some people treat coding
standards with religious zeal, and they try to get tools to generate code in their
local style. Forget it: if a tool generates code in a different style, don't worry about
it. Remember money and time?!? This whole coding standard thing was
supposed to save money and time; don't turn it into a "money pit."
Here are a few other sources that you can use as starting points for developing
your organization's coding standards (in random order) (some are out of date,
some might even be bad; I'm not endorsing any; caveat emptor):
• www.codingstandard.com/
• cdfsga.fnal.gov/computing/coding_guidelines/CodingGuidelines.html
• www.nfra.nl/~seg/cppStdDoc.html
• www.cs.umd.edu/users/cml/resources/cstyle
• www.cs.rice.edu/~dwallach/CPlusPlusStyle.html
• cpptips.hyperformix.com/conventions/cppconventions_1.html
• www.objectmentor.com/resources/articles/naming.htm
• www.arcticlabs.com/codingstandards/
• www.possibility.com/cpp/CppCodingStandard.html
• www.cs.umd.edu/users/cml/cstyle/Wildfire-C++Style.html
• Industrial Strength C++
• The Ellemtel coding guidelines are available at
o membres.lycos.fr/pierret/cpp2.htm
o www.cs.umd.edu/users/cml/cstyle/Ellemtel-rules.html
o www.doc.ic.ac.uk/lab/cplus/c++.rules/
o www.mgl.co.uk/people/kirit/cpprules.html
Notes:
• The Ellemtel guide is dated, but is listed because of its seminal place: it
was the first widely distributed and widely adopted set of coding guidelines
for C++. It was also the first to castigate the use of protected data.
• Industrial Strength C++ is also dated, but was the first widely published
place to mention the use of protected non-virtual destructors in base
classes.
Only when there is a compelling reason to do so. In other words, only when there
is no "normal" syntax that will produce the same end-result.
For example, the techniques used in the Obfuscated C Code Contest are, to be
polite, non-normal. Yes many of them are legal, but not everything that is legal is
moral. Using strange techniques will confuse other programmers. Some
programmers love to "show off" how far they can push the envelope, but that
puts their ego above money, and that's unprofessional. Frankly anybody who
does that ought to be fired. (And if you think I'm being "mean" or "cruel," I
suggest you get an attitude adjustment. Remember this: your company hired you
to help it, not to hurt it, and anybody who puts their own personal ego-trips above
their company's best interest simply ought to be shown the door.)
Same goes with using || and && as if they are "if-not" and "if" statements,
respectively. Yes, those are idioms in Perl, but C++ is not Perl and using these
as replacements for if statements (as opposed to using them as expressions) is
just not "normal" in C++. Example:
Here's another example that seems to work and may even be legal, but it's
certainly not normal:
Object-oriented thinking is caught, not just taught. Get cozy with someone who
really knows what they're talking about, and try to get inside their head and watch
them solve problems. Listen. Learn by emulating.
If you're working for a company, get them to bring someone in who can act as a
mentor and guide. We've seen gobs and gobs of money wasted by companies
who "saved money" by simply buying their employees a book ("Here's a book;
read it over the weekend; on Monday you'll be an OO developer").
Don't bother.
If your ultimate goal is to learn OO/C++ and you don't already know C, reading
books or taking courses in C will not only waste your time, but it will teach you a
bunch of things that you'll explicitly have to un-learn when you finally get back on
track and learn OO/C++ (e.g., malloc(), printf(), unnecessary use of switch
statements, error-code exception handling, unnecessary use of #define macros,
etc.).
If you want to learn OO/C++, learn OO/C++. Taking time out to learn C will waste
your time and confuse you.
Don't bother.
If your ultimate goal is to learn OO/C++ and you don't already know Smalltalk,
reading books or taking courses in Smalltalk will not only waste your time, but it
will teach you a bunch of things that you'll explicitly have to un-learn when you
finally get back on track and learn OO/C++ (e.g., dynamic typing, non-subtyping
inheritance, error-code exception handling, etc.).
Knowing a "pure" OO language doesn't make the transition to OO/C++ any
easier. This is not a theory; we have trained and mentored literally thousands of
software professionals in OO. In fact, Smalltalk experience can make it harder for
some people: they need to unlearn some rather deep notions about typing and
inheritance in addition to needing to learn new syntax and idioms. This
unlearning process is especially painful and slow for those who cling to Smalltalk
with religious zeal ("C++ is not like Smalltalk, therefore C++ is evil").
If you want to learn OO/C++, learn OO/C++. Taking time out to learn Smalltalk
will waste your time and confuse you.
Note: I sit on both the ANSI C++ (X3J16) and ANSI Smalltalk (X3J20)
standardization committees. I am not a language bigot. I'm not saying C++ is
better or worse than Smalltalk; I'm simply saying that they are different.
At least three.
Legality guides describe all language features with roughly the same level of
emphasis; morality guides focus on those language features that you will use
most often in typical programming tasks. Legality guides tell you how to get a
given feature past the compiler; morality guides tell you whether or not to use
that feature in the first place.
Meta comments:
• Don't trade off these categories against each other. You shouldn't argue in
favor of one category over the other. They dove-tail.
• The "legality" and "morality" categories are both required. You must have
a good grasp of both what can be done and what should be done.
In addition to these (emphasis on "addition"), you should consider at least one
book in each of two other categories: at least one book on OO Design plus at
least one book on coding standards. Design books give you ideas and guideliens
for thinking at a higher level with objects, and coding standard books establish
best practices across your organization, plus help make sure everybody can read
each others' code (e.g., so you can move people around if one of the teams falls
behind).
• Cline, Lomow, and Girou, C++ FAQs, Second Edition, 587 pgs, Addison-
Wesley, 1999, ISBN 0-201-30983-1. Covers around 500 topics in a FAQ-
like Q&A format.
• Meyers, Effective C++, Second Edition, 224 pgs, Addison-Wesley, 1998,
ISBN 0-201-92488-9. Covers 50 topics in a short essay format.
• Meyers, More Effective C++, 336 pgs, Addison-Wesley, 1996, ISBN 0-
201-63371-X. Covers 35 topics in a short essay format.
Similarities: All three books are extensively illustrated with code examples. All
three are excellent, insightful, useful, gold plated books. All three have excellent
sales records.
• Lippman, Lajoie and Moo, C++ Primer, Fourth Edition, 885 pgs, Addison-
Wesley, 2005, ISBN 0-201-72184-1. Very readable/approachable.
• Stroustrup, The C++ Programming Language, Third Edition, 911 pgs,
Addison-Wesley, 1998, ISBN 0-201-88954-4. Covers a lot of ground.
Similarities: Both books are excellent overviews of almost every language
feature. I reviewed them for back-to-back issues of C++ Report, and I said that
they are both top notch, gold plated, excellent books. Both have excellent sales
records.
Differences: If you don't know C, Lippman et al's book is better for you. If you
know C and you want to cover a lot of ground quickly, Stroustrup's book is better
for you.
• Koenig and Moo, Accelerated C++, 336 pgs, Addison-Wesley, 2000, ISBN
0-201-70353-X. Lots of examples using the standard C++ library. Truly a
programming-by-example book.
• Musser and Saini, STL Tutorial and Reference Guide, Second Edition,
Addison-Wesley, 2001, ISBN 0-201-037923-6. Lots of examples showing
how to use the STL portion of the standard C++ library, plus lots of nitty
gritty detail.
Yes! Tons!
The morality, legality, and by-example categories listed above were for OO
programming. The areas of OO analysis and OO design are also relevant, and
have their own best-of-breed books.
There are tons and tons of good books in these other areas. The seminal book
on OO design patterns is (in my personal, subjective and selective, opinion) a
must-read book: Gamma et al., Design Patterns, 395 pgs, Addison-Wesley,
1995, ISBN 0-201-63361-2. Describes "patterns" that commonly show up in good
OO designs. You must read this book if you intend to do OO design work.
It's a randomly ordered collection containing a few questions newbies might ask.
Hopefully someday I'll be able to improve this section, but for now, it is
incomplete and unorganized. If that bothers you, my suggestion is to click that
little x on the extreme upper right of your browser window :-).
Read the FAQ, especially the section on learning C++, read comp.lang.c++, read
books plural.
But if everything still seems too hard, if you're feeling bombarded with mysterious
terms and concepts, if you're wondering how you'll ever grasp anything, do this:
1. Type in some C++ code from any of the sources listed above.
2. Get it to compile and run.
3. Repeat.
That's it. Just practice and play. Hopefully that will give you a foothold.
Here are some places you can get "sample problems" (in alphabetical order):
int main()
main() must return int. Not void, not bool, not float. int. Just int, nothing but
int, only int.
Some compilers accept void main(), but that is non-standard and shouldn't be
used. Instead use int main().
As to the specific return value, if you don't know what else to return just say
return 0;
If you're writing C++ code, you should use f(). The f(void) style is legal in C++,
but only to make it easier to compile C code.
This C++ code shows the best way to declare a function that takes no
parameters:
This C++ code both declares and defines a function that takes no parameters:
void f(void); // undesirable style for C++; use void f() instead
Actually this f() thing is all you need to know about C++. That and using those
new fangled // comments. Once you know those two things, you can claim to be
a C++ expert. Go for it: type those magical "++" marks on your resumé. Who
cares about all that OO stuff — why should you bother changing the way you
think? After all, the really important thing isn't thinking; it's typing in function
declarations and comments. (Sigh; I wish nobody actually thought that way.)
[29.5] What are the criteria for choosing between short / int / long
data types?
Answer: It's usually a good idea to write code that can be ported to a different
operating system and/or compiler. After all, if you're successful at what you do,
someone else might want to use it somewhere else. This can be a little tricky with
built-in types like int and short, since C++ doesn't give guaranteed sizes.
However C++ gives you two things that might help: guaranteed minimum sizes,
and that will usually be all you need to know, and a standard C header that
provides typedefs for sized integers.
C++ guarantees a char is exactly one byte which is at least 8 bits, short is at
least 16 bits, int is at least 16 bits, and long is at least 32 bits. It also guarantees
the unsigned version of each of these is the same size as the original, for
example, sizeof(unsigned short) == sizeof(short).
When writing portable code, you shouldn't make additional assumptions about
these sizes. For example, don't assume int has 32 bits. If you have an integral
variable that needs at least 32 bits, use a long or unsigned long even if
sizeof(int) == 4 on your particular implementation. On the other hand, if you
have an integral variable quantity that will always fit within 16 bits and if you want
to minimize the use of data memory, use a short or unsigned short even if you
know sizeof(int) == 2 on your particular implementation.
The other option is to use the following standard C header (which may or may
not be provided by your C++ compiler vendor):
That header defines typedefs for things like int32_t and uint16_t, which are a
signed 32-bit integer and an unsigned 16-bit integer, respectively. There are
other goodies in there, as well. My recommendation is that you use these "sized"
integral types only where they are actually needed. Some people worship
consistency, and they are sorely tempted to use these sized integers everywhere
simply because they were needed somewhere. Consistency is good, but it is not
the greatest good, and using these typedefs everywhere can cause some
headaches and even possible performance issues. Better to use common sense,
which often leads you to use the normal keywords, e.g., int, unsigned, etc.
where you can, and use of the explicitly sized integer types, e.g., int32_t, etc.
where you must.
Note that there are some subtle tradeoffs here. In some cases, your computer
might be able to manipulate smaller things faster than bigger things, but in other
cases it is exactly the opposite: int arithmetic might be faster than short
arithmetic on some implementations. Another tradeoff is data-space against
code-space: int arithmetic might generate less binary code than short arithmetic
on some implementations. Don't make simplistic assumptions. Just because a
particular variable can be declared as short doesn't necessarily mean it should,
even if you're trying to save space.
Note that the C standard doesn't guarantee that <stdint.h> defines intn_t and
uintn_t specifically for n = 8, 16, 32 or 64. However if the underlying
implementation provides integers with any of those sizes, <stdint.h> is required
to contain the corresponding typedefs. Furthermore you are guaranteed to have
typedefs for sizes n = 8, 16 and 32 if your implementation is POSIX compliant.
Put all that together and it's fair to say that the vast majority of implementations,
though not all implementations, will have typedefs for those typical sizes.
The main issue is to figure out what it is; we can figure out what to call it later.
For example, consider the symbol max in the following function:
void f()
{
const int max = 107;
...
float array[max];
...
}
It doesn't matter whether you call max a const variable or a const identifier. What
matters is that you realize it is like a normal variable in some ways (e.g., you can
take its address or pass it by const-reference), but it is unlike a normal variable in
that you can't change its value.
class Fred {
public:
...
private:
static const int max_ = 107;
...
};
In this example, you would need to add the line int Fred::max_; in exactly
one .cpp file, typically in Fred.cpp.
In short, const identifiers act like they're part of the language because they are
part of the language. The preprocessor can be thought of as a language layered
on top of C++. You can imagine that the preprocessor runs as a separate pass
through your code, which would mean your original source code would be seen
only by the preprocessor, not by the C++ compiler itself. In other words, you can
imagine the preprocessor sees your original source code and replaces all
#define symbols with their values, then the C++ compiler proper sees the
modified source code after the original symbols got replaced by the
preprocessor.
There are cases where #define is needed, but you should generally avoid it
when you have the choice. You should evaluate whether to use const vs.
#define based on business value: time, money, risk. In other words, one size
does not fit all. Most of the time you'll use const rather than #define for
constants, but sometimes you'll use #define. But please remember to wash your
hands afterwards.
Every #define macro effectively creates a new keyword in every source file and
every scope until that symbol is #undefd. The preprocessor lets you create a
#define symbol that is always replaced independent of the {...} scope where that
symbol appears.
int main()
{
std::cout << "Hello world!\n";
...
}
[29.10] How should I lay out my code? When should I use spaces,
tabs, and/or newlines in my code?
The short answer is: Just like the rest of your team. In other words, the team
should use a consistent approach to whitespace, but otherwise please don't
waste a lot of time worrying about it.
if (foo()) {
bar();
baz();
}
if (foo())
{
bar();
baz();
}
if (foo())
{
bar();
baz();
}
if (foo())
{
bar();
baz();
}
if (foo()) {
bar();
baz();
}
...and others...
For example, things you should be worried about include design issues like when
ABCs should be used, whether inheritance should be an implementation or
specification technique, what testing and inspection strategies should be used,
whether interfaces should uniformly have a get() and/or set() member function
for each data member, whether interfaces should be designed from the outside-
in or the inside-out, whether errors be handled by try/catch/throw or by return
codes, etc. Read the FAQ for some opinions on those important questions, but
please don't waste your time arguing over whitespace. As long as the team is
using a consistent whitespace strategy, drop it.
Probably not.
In many (not all) cases, it's best to name your numbers so each number appears
only once in your code. That way, when the number changes there will only be
one place in the code that has to change.
For example, suppose your program is working with shipping crates. The weight
of an empty crate is 5.7. The expression 5.7 + contentsWeight probably means
the weight of the crate including its contents, meaning the number 5.7 probably
appear many times in the software. All these occurrences of the number 5.7 will
be difficult to find and change when (not if) somebody changes the style of crates
used in this application. The solution is to make sure the value 5.7 appears
exactly once, usually as the initializer for a const identifier. Typically this will be
something like const double crateWeight = 5.7;. After that, 5.7 +
contentsWeight would be replaced by crateWeight + contentsWeight.
Now that's the general rule of thumb. But unfortunately there is some fine print.
Some people believe one should never have numeric literals scattered in the
code. They believe all numeric values should be named in a manner similar to
that described above. That rule, however noble in intent, just doesn't work very
well in practice. It is too tedious for people to follow, and ultimately it costs
companies more than it saves them. Remember: the goal of all programming
rules is to reduce time, cost and risk. If a rule actually makes things worse, it is a
bad rule, period.
A more practical rule is to focus on those values that are likely to change. For
example, if a numeric literal is likely to change, it should appear only once in the
software, usually as the initializer of a const identifier. This rule lets unchanging
values, such as some occurrences of 0, 1, -1, etc., get coded directly in the
software so programmers don't have to search for the one true definition of one or
zero. In other words, if a programmer wants to loop over the indices of a vector,
he can simply write for (int i = 0; i < v.size(); ++i). The "extremist" rule
described earlier would require the programmer to poke around asking if
anybody else has defined a const identifier initialized to 0, and if not, to define his
own const int zero = 0; then replace the loop with for (int i = zero; i <
v.size(); ++i). This is all a waste of time since the loop will always start with 0.
It adds cost without adding any value to compensate for that cost.
Obviously people might argue over exactly which values are "likely to change,"
but that kind of judgment is why you get paid the big bucks: do your job and
make a decision. Some people are so afraid of making a wrong decision that
they'll adopt a one-size-fits-all rule such as "give a name to every number." But if
you adopt rules like that, you're guaranteed to have made the wrong decision:
those rules cost your company more than they save. They are bad rules.
The choice is simple: use a flexible rule even though you might make a wrong
decision, or use a one-size-fits-all rule and be guaranteed to make a wrong
decision.
There is one more piece of fine print: where the const identifier should be
defined. There are three typical cases:
• If the const identifier is used only within a single function, it can be local to
that function.
• If the const identifier is used throughout a class and no where else, it can
be static within the private part of that class.
• If the const identifier is used in numerous classes, it can be static within
the public part of the most appropriate class, or perhaps private in that
class with a public static access method.
(As used throughout the FAQ, "evil" doesn't mean "never use it." There are times
when you will use something that is "evil" since it will be, in those particular
cases, the lesser of two evils.)
You should use these suffixes when you need to force the compiler to treat the
numeric literal as if it were the specified type. For example, if x is of type float,
the expression x + 5.7 is of type double: it first promotes the value of x to a
double, then performs the arithmetic using double-precision instructions. If that is
what you want, fine; but if you really wanted it to do the arithmetic using single-
precision instructions, you can change that code to x + 5.7f. Note: it is even
better to "name" your numeric literals, particularly those that are likely to change.
That would require you to say x + crateWeight where crateWeight is a const
float that is initialized to 5.7f.
The U suffix is similar. It's probably a good idea to use unsigned integers for
variables that are always >= 0. For example, if a variable represents an index
into an array, that variable would typically be declared as an unsigned. The main
reason for this is it requires less code, at least if you are careful to check your
ranges. For example, to check if a variable is both >= 0 and < max requires two
tests if everything is signed: if (n >= 0 && n < max), but can be done with a
single comparison if everything is unsigned: if (n < max).
If you end up using unsigned variables, it is generally a good idea to force your
numeric literals to also be unsigned. That makes it easier to see that the compiler
will generate "unsigned arithmetic" instructions. For example: if (n < 256U) or
if ((n & 255u) < 32u). Mixing signed and unsigned values in a single
arithmetic expression is often confusing for programmers — the compiler doesn't
always do what you expect it should do.
The L suffix is not as common, but it is occasionally used for similar reasons as
above: to make it obvious that the compiler is using long arithmetic.
The bottom line is this: it is a good discipline for programmers to force all numeric
operands to be of the right type, as opposed to relying on the C++ rules for
promoting/demoting numeric expressions. For example, if x is of type int and y
is of type unsigned, it is a good idea to change x + y so the next programmer
knows whether you intended to use unsigned arithmetic, e.g., unsigned(x) + y,
or signed arithmetic: x + int(y). The other possibility is long arithmetic: long(x)
+ long(y). By using those casts, the code is more explicit and that's good in this
case, since a lot of programmers don't know all the rules for implicit promotions.
[29.13] I can understand the and (&&) and or (||) operators, but
what's the purpose of the not (!) operator?
Some people are confused about the ! operator. For example, they think that !
true is the same as false, or that !(a < b) is the same as a >= b, so in both
cases the ! operator doesn't seem to add anything.
if ( A && B) ...
if (!A && B) ...
if ( A && !B) ...
if (!A && !B) ...
if (!( A && B)) ...
if (!(!A && B)) ...
if (!( A && !B)) ...
if (!(!A && !B)) ...
Note: boolean algebra can be used to transform each of the &&-versions into an
equivalent ||-version, so from a truth-table standpoint there are only 8 logically
distinct if statements. However, since readability is so important in software,
programmers should consider both the &&-version and the logically equivalent ||-
version. For example, programmers should choose between !A && !B and !(A
|| B) based on which one is more obvious to whoever will be maintaining the
code. In that sense there really are 16 different choices.
The point of all this is simple: the ! operator is quite useful in boolean
expressions. Sometimes it is used for readability, and sometimes it is used
because expressions like !(a < b) actually are not equivalent to a >= b in spite
of what your grade school math teacher told you.
No!
Despite what your grade school math teacher taught you, these equivalences
don't always work in software, especially with floating point expressions or user-
defined types.
Example: if a is a floating point NaN, then both a < b and a >= b will be false.
That means !(a < b) will be true and a >= b will be false.
NaN means "not a number," and is used for floating point operations.
There are lots of floating point operations that don't make sense, such as dividing
by zero, taking the log of zero or a negative number, taking the square root of a
negative number, etc. Depending on your compiler, some of these operations
may produce special floating point values such as infinity (with distinct values for
positive vs. negative infinity) and the not a number value, NaN.
If your compiler produces a NaN, it has the unusual property that it is not equal to
any value, including itself. For example, if a is NaN, then a == a is false. In fact, if
a is NaN, then a will be neither less than, equal to, nor greater than any value
including itself. In other words, regardless of the value of b, a < b, a <= b, a > b,
a >= b, and a == b will all return false.
#include <cmath>
void funct(double x)
{
if (isnan(x)) { ← though see caveat below
// x is NaN
...
} else {
// x is a normal value
...
}
}
Note: although isnan() is part of the latest C standard library, your C++ compiler
vendor might not supply it. For example, Microsoft Visual C++.NET does not
supply isnan() (though it does supply _isnan() defined in <float.h>). If your
vendor does not supply any variant of isnan(), define this function:
In any case, DO NOT WRITE ME just to say that your compiler does/does not
support isnan().
int main()
{
float a = 1000.43;
float b = 1000.0;
std::cout << a - b << '\n';
...
}
Answer: Floating point is an approximation. The IEEE standard for 32 bit float
supports 1 bit of sign, 8 bits of exponent, and 23 bits of mantissa. Since a
normalized binary-point mantissa always has the form 1.xxxxx... the leading 1 is
dropped and you get effectively 24 bits of mantissa. The number 1000.43 (and
many, many others, including some really common ones like 0.1) is not exactly
representable in float or double format. 1000.43 is actually represented as the
following bitpattern (the "s" shows the position of the sign bit, the "e"s show the
positions of the exponent bits, and the " m"s show the positions of the mantissa
bits):
seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
01000100011110100001101110000101
The above "surprise" message will appear on some (but not all)
compilers/machines. But even if your particular compiler/machine doesn't cause
the above "surprise" message (and if you write me telling me whether it does,
you'll show you've missed the whole point of this FAQ), floating point will surprise
you at some point. So read this FAQ and you'll know what to do.
The reason floating point will surprise you is that float and double values are
normally represented using a finite precision binary format. In other words,
floating point numbers are not real numbers. For example, in your machine's
floating point format it might be impossible to exactly represent the number 0.1.
By way of analogy, it's impossible to exactly represent the number one third in
decimal format (unless you use an infinite number of digits).
To dig a little deeper, let's examine what the decimal number 0.625 means. This
number has a 6 in the "tenths" place, a 2 in the "hundreths" place, and a 5 in the
"thousanths" place. In other words, we have a digit for each power of 10. But in
binary, we might, depending on the details of your machine's floating point
format, have a bit for each power of 2. So the fractional part might have a
"halves" place, a "quarters" place, an "eighths" place, "sixteenths" place, etc.,
and each of these places has a bit.
Let's pretend your machine represents the fractional part of floating point
numbers using the above scheme (it's normally more complicated than that, but if
you already know exactly how floating point numbers are stored, chances are
you don't need this FAQ to begin with, so look at this as a good starting point).
On that pretend machine, the bits of the fractional part of 0.625 would be 101: 1
in the ½-place, 0 in the ¼-place, and 1 in the ⅛-place. In other words, 0.625 is ½
+ ⅛.
But on this pretend machine, 0.1 cannot be represented exactly since it cannot
be formed as a sum of a finite number of powers of 2. You can get close but you
can't represent it exactly. In particular you'd have a 0 in the ½-place, a 0 in the ¼-
place, a 0 in the ⅛-place, and finally a 1 in the "sixteenths" place, leaving a
remainder of 1/10 - 1/16 = 3/80. Figuring out the other bits is left as an exercise
(hint: look for a repeating bit-pattern, analogous to trying to represent 1/3 or 1/7
in decimal format).
The message is that some floating point numbers cannot always be represented
exactly, so comparisons don't always do what you'd like them to do. In other
words, if the computer actually multiplies 10.0 by 1.0/10.0, it might not exactly get
1.0 back.
That's the problem. Now here's the solution: be very careful when comparing
floating point numbers for equality (or when doing other things with floating point
numbers; e.g., finding the average of two floating point numbers seems simple
but to do it right requires an if/else with at least three cases).
If what you really want is to make sure they're "very close" to each other (e.g., if
variable a contains the value 1.0 / 10.0 and you want to see if (10*a == 1)),
you'll probably want to do something fancier than the above:
Note: the above solution is not completely symmetric, meaning it is possible for
isEqual(x,y) != isEqual(y,x). From a practical standpoint, does not usually
occur when the magnitudes of x and y are significantly larger than epsilon, but
your mileage may vary.
For other useful functions, check out the following (listed alphabetically):
For insights on the underlying ideas and issues of floating point computation,
start with David Goldberg's paper, What Every Computer-Scientist Should Know
About Floating Point Arithmetic or here in PDF format. You might also want to
read this supplement by Doug Priest. The combined paper + supplement is also
available. You might also want to go here for links to other floating-point topics.
Let's work a simple example. Turns out that on some installations, cos(x) !=
cos(y) even though x == y. That's not a typo; read it again if you're not shocked:
the cosine of something can be unequal to the cosine of the same thing. (Or the
sine, or the tangent, or the log, or just about any other floating point
computation.)
#include <cmath>
int main()
{
foo(1.0, 1.0);
return 0;
}
On many (not all) computers, you will end up in the if block even when x == y. If
that doesn't shock you, you're asleep; read it again. If you want, try it on your
particular computer. Some of you will end up in the if block, some will not, and
for some it will depend on the details of your particular compiler or options or
hardware or the phase of the moon.
{bold{Why}bold}, you ask, can that happen? Good question; thanks for asking.
Here's the answer (with emphasis on the word "often"; the behavior depends on
your hardware, compiler, etc.): floating point calculations and comparisons are
often performed by special hardware that often contain special registers, and
those registers often have more bits than a double. That means that intermediate
floating point computations often have more bits than sizeof(double), and when
a floating point value is written to RAM, it often gets truncated, often losing some
bits of precision.
Said another way, intermediate calculations are often more precise (have more
bits) than when those same values get stored into RAM. Think of it this way:
storing a floating point result into RAM requires some bits to get discarded, so
comparing a (truncated) value in RAM with an (untruncated) value within a
floating-point register might not do what you expect. Suppose your code
computes cos(x), then truncates that result and stores it into a temporary
variable, say tmp. It might then compute cos(y), and (drum roll please) compare
the untruncated result of cos(y) with tmp, that is, with the truncated result of
cos(x). Expressed in an imaginary assembly language, the expression cos(x) !
= cos(y) might get compiled into this:
Did you catch that? Your particular installation might store the result of one of the
cos() calls out into RAM, truncating it in the process, then later compare that
truncated value with the untruncated result of the second cos() call. Depending
on lots of details, those two values might not be equal.
{bold{It gets worse}bold}; better sit down. Turns out that the behavior can depend
on how many instructions are between the cos() calls and the != comparison. In
other words, if you put cos(x) and cos(y) into locals, then later compare those
variables, the result of the comparison can depend on exactly what, if anything,
your code does after storing the results into locals and comparing the variables.
Gulp.
Your mouth should be hanging open by now. If not, you either learned pretty
quickly from the above or you are still asleep. Read it again. When x == y, you
can still end up in the if block depending on, among other things, how much
code is in the ... line. Wow.
{bold{Reason:}bold} if the compiler can prove that you're not messing with any
floating point registers in the ... line, it might not actually store cos(y) into cos_y,
instead leaving it in the register and comparing the untruncated register with the
truncated variable cos_x. In this case, you might end up in the if block. But if you
call a function between the two lines, such as printing one or both variables, or if
you do something else that messes with the floating point registers, the compiler
will (might) need to store the result of cos(y) into variable cos_y, after which it will
be comparing two truncated values. In that case you won't end up in the if block.
If you didn't hear anything else in this whole discussion, just remember this:
floating point comparisons are tricky and subtle and fraught with danger. Be
careful. The way floating point actually works is different from the way most
programmers tend to think it ought to work. If you intend to use floating point, you
need to learn how it actually works.
An enumeration such as enum Color { red, white, blue }; is its own type. It is
not of type int.
When you create an object of an enumeration type, e.g., Color x;, we say that
the object x is of type Color. Object x isn't of type "enumeration," and it's not of
type int.
The above conversion is very different from a subtype relationship, such as the
relationship between derived class Car and its base class Vehicle. For example,
an object of class Car, such as Car z;, actually is an object of class Vehicle,
therefore you can bind a Vehicle& to that object, e.g., Vehicle& v = z;. Unlike
the previous paragraph, the object z is not copied to a temporary; reference v
binds to z itself. So we say an object of class Car is a Vehicle, but an object of
class "Color" simply can be copied/converted into a temporary int. Big
difference.
Final note, especially for C programmers: the C++ compiler will not automatically
convert an int expression to a temporary Color. Since that sort of conversion is
unsafe, it requires a cast, e.g., Color x = Color(2);. But be sure your integer is
a valid enumeration value. If you go provide an illegal value, you might end up
with something other than what you expect. The compiler doesn't do the check
for you; you must do it yourself.
Let's consider this enumeration type: enum Color { red, white, blue };.
The best way to look at this (C programmers: hang on to your seats!!) is that the
values of this type are red, white, and blue, as opposed to merely thinking of
those names as constant int values. The C++ compiler provides an automatic
conversion from Color to int, and the converted values will be, in this case, 0, 1,
and 2 respectively. But you shouldn't think of blue as a fancy name for 2. blue is
of type Color and there is an automatic conversion from blue to 2, but the
inverse conversion, from int to Color, is not provided automatically by the C++
compiler.
void f()
{
int n;
n = red; // change n to 0
n = white; // change n to 1
n = blue; // change n to 2
}
The following example also demonstrates the conversion from Color to int:
void f()
{
Color x = red;
Color y = white;
Color z = blue;
int n;
n = x; // change n to 0
n = y; // change n to 1
n = z; // change n to 2
}
However the inverse conversion, from int to Color, is not automatically provided
by the C++ compiler:
void f()
{
Color x;
x = blue; // change x to blue
x = 2; // compile-time error: can't convert int to Color
}
The last line above shows that enumeration types are not ints in disguise. You
can think of them as int types if you want to, but if you do, you must remember
that the C++ compiler will not implicitly convert an int to a Color. If you really
want that, you can use a cast:
void f()
{
Color x;
x = red; // change x to red
x = Color(1); // change x to white
x = Color(2); // change x to blue
x = 2; // compile-time error: can't convert int to Color
}
There are other ways that enumeration types are unlike int. For example,
enumeration types don't have a ++ operator:
void f()
{
int n = red; // change n to 0
Color x = red; // change x to red
n++; // change n to 1
x++; // compile-time error: can't ++ an enumeration (though see caveat below)
}
Caveat on the last line: it is legal to provide an overloaded operator that would
make that line legal, such as definining operator++(Color& x).
Pros of value semantics: speed. "Speed" seems like an odd benefit for a feature
that requires an object (vs. a pointer) to be copied, but the fact of the matter is
that one usually accesses an object more than one copies the object, so the cost
of the occasional copies is (usually) more than offset by the benefit of having an
actual object rather than a pointer to an object.
There are three cases when you have an actual object as opposed to a pointer to
an object: local objects, global/static objects, and fully contained member
objects in a class. The most important of these is the last ("composition").
More info about copy-vs-reference semantics is given in the next FAQs. Please
read them all to get a balanced perspective. The first few have intentionally been
slanted toward value semantics, so if you only read the first few of the following
FAQs, you'll get a warped perspective.
Assignment has other issues (e.g., shallow vs. deep copy) which are not covered
here.
virtual data allows a derived class to change the exact class of a base class's
member object. virtual data isn't strictly "supported" by C++, however it can be
simulated in C++. It ain't pretty, but it works.
To simulate virtual data in C++, the base class must have a pointer to the
member object, and the derived class must provide a new object to be pointed to
by the base class's pointer. The base class would also have one or more normal
constructors that provide their own referent (again via new), and the base class's
destructor would delete the referent.
For example, class Stack might have an Array member object (using a pointer),
and derived class StretchableStack might override the base class member data
from Array to StretchableArray. For this to work, StretchableArray would have
to inherit from Array, so Stack would have an Array*. Stack's normal
constructors would initialize this Array* with a new Array, but Stack would also
have a (possibly protected) constructor that would accept an Array* from a
derived class. StretchableStack's constructor would provide a new
StretchableArray to this special constructor.
Pros:
Cons:
Please read the rest of this section. (You will not get a balanced perspective
without the others.)
The easiest way to see the distinction is by an analogy with virtual functions: A
virtual member function means the declaration (signature) must stay the same
in derived classes, but the definition (body) can be overridden. The
overriddenness of an inherited member function is a static property of the derived
class; it doesn't change dynamically throughout the life of any particular object,
nor is it possible for distinct objects of the derived class to have distinct
definitions of the member function.
Now go back and re-read the previous paragraph, but make these substitutions:
Extending the analogy, this gives us three distinct concepts for data members:
The reason they all look so much the same is that none of this is "supported" in
C++. It's all merely "allowed," and in this case, the mechanism for faking each of
these is the same: a pointer to a (probably abstract) base class. In a language
that made these "first class" abstraction mechanisms, the difference would be
more striking, since they'd each have a different syntactic variant.
Composition.
There are three reasons why fully contained member objects ("composition") has
better performance than pointers to freestore-allocated member objects:
• Extra layer of indirection every time you need to access the member
object
• Extra freestore allocations (new in constructor, delete in destructor)
• Extra dynamic binding (reason given below)
Note: Please read the next three FAQs to get a balanced perspective!
Occasionally...
Therefore the only time an inline virtual call can be inlined is when the
compiler knows the "exact class" of the object which is the target of the virtual
function call. This can happen only when the compiler has an actual object rather
than a pointer or reference to an object. I.e., either with a local object, a
global/static object, or a fully contained object inside a composite.
Note that the difference between inlining and non-inlining is normally much more
significant than the difference between a regular function call and a virtual
function call. For example, the difference between a regular function call and a
virtual function call is often just two extra memory references, but the difference
between an inline function and a non-inline function can be as much as an
order of magnitude (for zillions of calls to insignificant member functions, loss of
inlining virtual functions can result in 25X speed degradation! [Doug Lea,
"Customization in C++," proc Usenix C++ 1990]).
A practical consequence of this insight: don't get bogged down in the endless
debates (or sales tactics!) of compiler/language vendors who compare the cost of
a virtual function call on their language/compiler with the same on another
language/compiler. Such comparisons are largely meaningless when compared
with the ability of the language/compiler to "inline expand" member function
calls. I.e., many language implementation vendors make a big stink about how
good their dispatch strategy is, but if these implementations don't inline member
function calls, the overall system performance would be poor, since it is inlining
—not dispatching— that has the greatest performance impact.
Note: Please read the next two FAQs to see the other side of this coin!
Wrong.
Reference semantics are A Good Thing. We can't live without pointers. We just
don't want our software to be One Gigantic Rats Nest Of Pointers. In C++, you
can pick and choose where you want reference semantics (pointers/references)
and where you'd like value semantics (where objects physically contain other
objects etc). In a large system, there should be a balance. However if you
implement absolutely everything as a pointer, you'll get enormous speed hits.
Objects near the problem skin are larger than higher level objects. The identity of
these "problem space" abstractions is usually more important than their "value."
Thus reference semantics should be used for problem-space objects.
Note that these problem space objects are normally at a higher level of
abstraction than the solution space objects, so the problem space objects
normally have a relatively lower frequency of interaction. Therefore C++ gives us
an ideal situation: we choose reference semantics for objects that need unique
identity or that are too large to copy, and we can choose value semantics for the
others. Thus the highest frequency objects will end up with value semantics,
since we install flexibility where it doesn't hurt us (only), and we install
performance where we need it most!
These are some of the many issues the come into play with real OO design.
OO/C++ mastery takes time and high quality training. If you want a powerful tool,
you've got to invest.
Nope.
The previous FAQ were talking about member objects, not parameters.
Generally, objects that are part of an inheritance hierarchy should be passed by
reference or by pointer, not by value, since only then do you get the (desired)
dynamic binding (pass-by-value doesn't mix with inheritance, since larger derived
class objects get sliced when passed by value as a base class object).
Unless compelling reasons are given to the contrary, member objects should be
by value and parameters should be by reference. The discussion in the previous
few FAQs indicates some of the "compelling reasons" for when member objects
should be by reference.
Here are some high points (though some compiler-vendors might not require all
these; check with your compiler-vendor's documentation):
• You must use your C++ compiler when compiling main() (e.g., for static
initialization)
• Your C++ compiler should direct the linking process (e.g., so it can get its
special libraries)
• Your C and C++ compilers probably need to come from same vendor and
have compatible versions (e.g., so they have the same calling
conventions)
In addition, you'll need to read the rest of this section to find out how to make
your C functions callable by C++ and/or your C++ functions callable by C.
BTW there is another way to handle this whole thing: compile all your code (even
your C-style code) using a C++ compiler. That pretty much eliminates the need to
mix C and C++, plus it will cause you to be more careful (and possibly —
hopefully!— discover some bugs) in your C-style code. The down-side is that
you'll need to update your C-style code in certain ways, basically because the C+
+ compiler is more careful/picky than your C compiler. The point is that the effort
required to clean up your C-style code may be less than the effort required to mix
C and C++, and as a bonus you get cleaned up C-style code. Obviously you
don't have much of a choice if you're not able to alter your C-style code (e.g., if
it's from a third-party).
int main()
{
std::printf("Hello world\n"); // Nothing unusual in the call either
...
}
If you think the std:: part of the std::printf() call is unusual, then the best
thing to do is "get over it." In other words, it's the standard way to use names in
the standard library, so you might as well start getting used to it now.
However if you are compiling C code using your C++ compiler, you don't want to
have to tweak all these calls from printf() to std::printf(). Fortunately in this
case the C code will use the old-style header <stdio.h> rather than the new-style
header <cstdio>, and the magic of namespaces will take care of everything else:
int main()
{
printf("Hello world\n"); /* Nothing unusual in the call either */
...
}
Final comment: if you have C headers that are not part of the standard library, we
have somewhat different guidelines for you. There are two cases: either you
can't change the header, or you can change the header.
If you are including a C header file that isn't provided by the system, you may
need to wrap the #include line in an extern "C" { /*...*/ } construct. This tells
the C++ compiler that the functions declared in the header file are C functions.
// This is C++ code
extern "C" {
// Get declaration for f(int i, char c, float x)
#include "my-C-code.h"
}
int main()
{
f(7, 'x', 3.14); // Note: nothing unusual in the call
...
}
Note: Somewhat different guidelines apply for C headers provided by the system
(such as <cstdio>) and for C headers that you can change.
If you are including a C header file that isn't provided by the system, and if you
are able to change the C header, you should strongly consider adding the extern
"C" {...} logic inside the header to make it easier for C++ users to #include it
into their C++ code. Since a C compiler won't understand the extern "C"
construct, you must wrap the extern "C" { and } lines in an #ifdef so they won't
be seen by normal C compilers.
Step #1: Put the following lines at the very top of your C header file (note: the
symbol __cplusplus is #defined if/only-if the compiler is a C++ compiler):
#ifdef __cplusplus
extern "C" {
#endif
Step #2: Put the following lines at the very bottom of your C header file:
#ifdef __cplusplus
}
#endif
Now you can #include your C header without any extern "C" nonsense in your
C++ code:
Note: Somewhat different guidelines apply for C headers provided by the system
(such as <cstdio>) and for C headers that you can't change.
Note: #define macros are evil in 4 different ways: evil#1, evil#2, evil#3, and
evil#4. But they're still useful sometimes. Just wash your hands after using them.
If you have an individual C function that you want to call, and for some reason
you don't have or don't want to #include a C header file in which that function is
declared, you can declare the individual C function in your C++ code using the
extern "C" syntax. Naturally you need to use the full function prototype:
extern "C" {
void f(int i, char c, float x);
int g(char* s, const char* s2);
double sqrtOfSumOfSquares(double a, double b);
}
After this you simply call the function just as if it were a C++ function:
int main()
{
f(7, 'x', 3.14); // Note: nothing unusual in the call
...
}
...
The extern "C" line tells the compiler that the external information sent to the
linker should use C calling conventions and name mangling (e.g., preceded by a
single underscore). Since name overloading isn't supported by C, you can't make
several overloaded functions simultaneously callable by a C program.
[32.7] Why is the linker giving errors for C/C++ functions being
called from C++/C functions?
If you didn't get your extern "C" right, you'll sometimes get linker errors rather
than compiler errors. This is due to the fact that C++ compilers usually "mangle"
function names (e.g., to support function overloading) differently than C
compilers.
Here's an example (for info on extern "C", see the previous two FAQs).
Fred.h:
#ifdef __cplusplus
class Fred {
public:
Fred();
void wilma(int);
private:
int a_;
};
#else
typedef
struct Fred
Fred;
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /*FRED_H*/
Fred.cpp:
#include "Fred.h"
Fred::Fred() : a_(0) { }
void Fred::wilma(int a) { }
main.cpp:
#include "Fred.h"
int main()
{
Fred fred;
c_function(&fred);
...
}
c-function.c:
/* This is C code */
#include "Fred.h"
Unlike your C++ code, your C code will not be able to tell that two pointers point
at the same object unless the pointers are exactly the same type. For example, in
C++ it is easy to check if a Derived* called dp points to the same object as is
pointed to by a Base* called bp: just say if (dp == bp) .... The C++ compiler
automatically converts both pointers to the same type, in this case to Base*, then
compares them. Depending on the C++ compiler's implementation details, this
conversion sometimes changes the bits of a pointer's value. However your C
compiler will not know how to do that pointer conversion, so the conversion from
Derived* to Base*, for example, must take place in code compiled with a C++
compiler, not in code compiled with a C compiler.
NOTE: you must be especially careful when converting both to void* since that
conversion will not allow either the C or C++ compiler to do the proper pointer
adjustments! For example (continuing from the previous paragraph), if you
assigned dp and bp into two void* pointers, say dpv and bpv, it might be the case
that dpv != bpv even if dp == bp. You have been warned.
Sometimes.
(For basic info on passing C++ objects to/from C functions, read the previous
FAQ).
You can safely access a C++ object's data from a C function if the C++ class:
If the C++ class has any base classes at all (or if any fully contained subobjects
have base classes), accessing the data will technically be non-portable, since
class layout under inheritance isn't imposed by the language. However in
practice, all C++ compilers do it the same way: the base class object appears
first (in left-to-right order in the event of multiple inheritance), and member
objects follow.
Furthermore, if the class (or any base class) contains any virtual functions,
almost all C++ compliers put a void* into the object either at the location of the
first virtual function or at the very beginning of the object. Again, this is not
required by the language, but it is the way "everyone" does it.
If the class has any virtual base classes, it is even more complicated and less
portable. One common implementation technique is for objects to contain an
object of the virtual base class (V) last (regardless of where V shows up as a
virtual base class in the inheritance hierarchy). The rest of the object's parts
appear in the normal order. Every derived class that has V as a virtual base
class actually has a pointer to the V part of the final object.
[32.10] Why do I feel like I'm "further from the machine" in C++ as
opposed to C?
One of C's great strengths is the fact that it has "no hidden mechanism": what
you see is what you get. You can read a C program and "see" every clock cycle.
This is not the case in C++; old line C programmers (such as many of us once
were) are often ambivalent (can you say, "hostile"?) about this feature. However
after they've made the transition to OO thinking, they often realize that although
C++ hides some mechanism from the programmer, it also provides a level of
abstraction and economy of expression which lowers maintenance costs without
destroying run-time performance.
Naturally you can write bad code in any language; C++ doesn't guarantee any
particular level of quality, reusability, abstraction, or any other measure of
"goodness."
C++ doesn't try to make it impossible for bad programmers to write bad
programs; it enables reasonable developers to create superior software.
Yep.
Note: if it's a static member function of class Fred, its type is the same as if it
were an ordinary function: "int (*)(char,float)".
Don't.
Here's an example of the worst case (using a global). Suppose you want to call
Fred::memberFn() on interrupt:
class Fred {
public:
void memberFn();
static void staticMemberFn(); // A static member function can usually handl
e it
...
};
// Wrapper function uses a global to remember the object:
Fred* object_which_will_handle_signal;
void Fred_memberFn_wrapper()
{
object_which_will_handle_signal->memberFn();
}
int main()
{
/* signal(SIGINT, Fred::memberFn); */ // Can NOT do this
signal(SIGINT, Fred_memberFn_wrapper); // OK
signal(SIGINT, Fred::staticMemberFn); // OK usually; see below
...
}
This is a special case of the previous two questions, therefore read the previous
two answers first.
One possible solution is to use a static member as the interrupt service routine
and have that function look somewhere to find the instance/member pair that
should be called on interrupt. Thus the effect is that a member function is invoked
on an interrupt, but for technical reasons you need to call an intermediate
function first.
Short answer: if you're trying to store it into (or pass it as) a pointer-to-function,
then that's the problem — this is a corollary to the previous FAQ.
Long answer: In C++, member functions have an implicit parameter which points
to the object (the this pointer inside the member function). Normal C functions
can be thought of as having a different calling convention from member
functions, so the types of their pointers (pointer-to-member-function vs. pointer-
to-function) are different and incompatible. C++ introduces a new type of pointer,
called a pointer-to-member, which can be invoked only by providing an object.
class Fred {
public:
int f(char x, float y);
int g(char x, float y);
int h(char x, float y);
int i(char x, float y);
...
};
...
}
Note: #define macros are evil in 4 different ways: evil#1, evil#2, evil#3, and
evil#4. But they're still useful sometimes. But you should still feel a vague sense
of shame after using them.
Use both the typedef and the #define macro described earlier, and you're 90%
done.
class Fred {
public:
int f(char x, float y);
int g(char x, float y);
int h(char x, float y);
int i(char x, float y);
...
};
And your usage of one of the member function pointers is also straightforward:
Note: #define macros are evil in 4 different ways: evil#1, evil#2, evil#3, and
evil#4. But they're still useful sometimes. Feel ashamed, feel guilty, but when an
evil construct like a macro improves your software, use it.
No!
class Fred {
public:
int f(char x, float y);
int g(char x, float y);
int h(char x, float y);
int i(char x, float y);
...
};
int main()
{
FredMemFn p = &Fred::f;
void* p2 = (void*)p; // ← illegal!!
Fred o;
callit(o, p, 'x', 3.14f); // okay
callit(o, FredMemFn(p2), 'x', 3.14f); // might fail!!
...
}
Please do not email me if the above seems to work on your particular version of
your particular compiler on your particular operating system. I don't care. It's
illegal, period.
No!
typedef int(*FunctPtr)(char,float);
int main()
{
FunctPtr p = f;
void* p2 = (void*)p; // ← illegal!!
callit(p, 'x', 3.14f); // okay
callit(FunctPtr(p2), 'x', 3.14f); // might fail!!
...
}
Please do not email me if the above seems to work on your particular version of
your particular compiler on your particular operating system. I don't care. It's
illegal, period.
Use a functionoid.
[33.10] What the heck is a functionoid, and why would I use one?
Functionoids are functions on steroids. Functionoids are strictly more powerful
than functions, and that extra power solves some (not all) of the challenges
typically faced when you use function-pointers.
typedef int(*FunctPtr)(...params...);
void myCode(FunctPtr f)
{
...
f(...args-go-here...);
...
}
FunctPtr array[10];
array[0] = funct1;
array[1] = funct1;
array[2] = funct3;
array[3] = funct2;
...
array[i](...args-go-here...);
With functionoids, you first create a base class with a pure-virtual method:
class Funct {
public:
virtual int doit(int x) = 0;
virtual ~Funct() = 0;
};
inline Funct::~Funct() { } // defined even though it's pure virtual; it's faster this way;
trust me
void myCode(FunctPtr f)
{
...
f->doit(...args-go-here...);
...
}
FunctPtr array[10];
array[0] = new Funct1(...ctor-args...);
array[1] = new Funct1(...ctor-args...);
array[2] = new Funct3(...ctor-args...);
array[3] = new Funct2(...ctor-args...);
...
This gives us the first hint about where functionoids are strictly more powerful
than function-pointers: the fact that the functionoid approach has arguments you
can pass to the ctors (shown above as ...ctor-args...) whereas the function-
pointers version does not. Think of a functionoid object as a freeze-dried
function-call (emphasis on the word call). Unlike a pointer to a function, a
functionoid is (conceptually) a pointer to a partially called function. Imagine for
the moment a technology that lets you pass some-but-not-all arguments to a
function, then lets you freeze-dry that (partially completed) call. Pretend that
technology gives you back some sort of magic pointer to that freeze-dried
partially-completed function-call. Then later you pass the remaining args using
that pointer, and the system magically takes your original args (that were freeze-
dried), combines them with any local variables that the function calculated prior
to being freeze-dried, combines all that with the newly passed args, and
continues the function's execution where it left off when it was freeze-dried. That
might sound like science fiction, but it's conceptually what functionoids let you do.
Plus they let you repeatedly "complete" that freeze-dried function-call with
various different "remaining parameters," as often as you like. Plus they allow
(not require) you to change the freeze-dried state when it gets called, meaning
functionoids can remember information from one call to the next.
Okay, let's get our feet back on the ground and we'll work a couple of examples
to explain what all that mumbo jumbo really means.
Suppose the original functions (in the old-fashioned function-pointer style) took
slightly different parameters.
With functionoids, the situation is, at least sometimes, much better. Since a
functionoid can be thought of as a freeze-dried function call, just take the un-
common args, such as the ones I've called y and/or z, and make them args to the
corresponding ctors. You may also pass the common args (in this case the int
called x) to the ctor, but you don't have to — you have the option of passing
it/them to the pure virtual doit() method instead. I'll assume you want to pass x
and into doit() and y and/or z into the ctors:
class Funct {
public:
virtual int doit(int x) = 0;
};
Now you see that the ctor's parameters get freeze-dried into the functionoid when
you create the array of functionoids:
FunctPtr array[10];
std::vector<double> bottlesOfBeerOnTheWall;
bottlesOfBeerOnTheWall.push_back(100);
bottlesOfBeerOnTheWall.push_back(99);
...
bottlesOfBeerOnTheWall.push_back(1);
array[2] = new Funct3(bottlesOfBeerOnTheWall);
...
So when the user invokes the doit() on one of these functionoids, he supplies
the "remaining" args, and the call conceptually combines the original args passed
to the ctor with those passed into the doit() method:
array[i]->doit(12);
As I've already hinted, one of the benefits of functionoids is that you can have
several instances of, say, Funct1 in your array, and those instances can have
different parameters freeze-dried into them. For example, array[0] and array[1]
are both of type Funct1, but the behavior of array[0]->doit(12) will be different
from the behavior of array[1]->doit(12) since the behavior will depend on both
the 12 that was passed to doit() and the args passed to the ctors.
Another benefit of functionoids is apparent if we change the example from an
array of functionoids to a local functionoid. To set the stage, let's go back to the
old-fashioned function-pointer approach, and imagine that you're trying to pass a
comparison-function to a sort() or binarySearch() routine. The sort() or
binarySearch() routine is called childRoutine() and the comparison function-
pointer type is called FunctPtr:
void childRoutine(FunctPtr f)
{
...
f(...args...);
...
}
void myCaller()
{
...
childRoutine(funct1);
...
}
void yourCaller()
{
...
childRoutine(funct3);
...
}
void childRoutine(Funct& f)
{
...
f.doit(...args...);
...
}
void myCaller()
{
...
Funct1 funct(...ctor-args...);
childRoutine(funct);
...
}
void yourCaller()
{
...
Funct3 funct(...ctor-args...);
childRoutine(funct);
...
}
Given this example as a backdrop, we can see two benefits of functionoids over
function-pointers. The "ctor args" benefit described above, plus the fact that
functionoids can maintain state between calls in a thread-safe manner. With plain
function-pointers, people normally maintain state between calls via static data.
However static data is not intrinsically thread-safe — static data is shared
between all threads. The functionoid approach provides you with something that
is intrinsically thread-safe since the code ends up with thread-local data. The
implementation is trivial: change the old-fashioned static datum to an instance
data member inside the functionoid's this object, and poof, the data is not only
thread-local, but it is even safe with recursive calls: each call to yourCaller() will
have its own distinct Funct3 object with its own distinct instance data.
Note that we've gained something without losing anything. If you want thread-
global data, functionoids can give you that too: just change it from an instance
data member inside the functionoid's this object to a static data member within
the functionoid's class, or even to a local-scope static data. You'd be no better off
than with function-pointers, but you wouldn't be worse off either.
The functionoid approach gives you a third option which is not available with the
old-fashioned approach: the functionoid lets callers decide whether they want
thread-local or thread-global data. They'd be responsible to use locks in cases
where they wanted thread-global data, but at least they'd have the choice. It's
easy:
void callerWithThreadLocalData()
{
...
Funct1 funct(...ctor-args...);
childRoutine(funct);
...
}
void callerWithThreadGlobalData()
{
...
static Funct1 funct(...ctor-args...); ← the static is the only difference
childRoutine(funct);
...
}
Yes.
If you have a small functionoid, and in the real world that's rather common, the
cost of the function-call can be high compared to the cost of the work done by the
functionoid. In the previous FAQ, functionoids were implemented using virtual
functions and will typically cost you a function-call. An alternate approach uses
templates.
The following example is similar in spirit to the one in the previous FAQ. I have
renamed doit() to operator()() to improve the caller code's readability and to
allow someone to pass a regular function-pointer:
class Funct1 {
public:
Funct1(float y) : y_(y) { }
int operator()(int x) { ...code from funct1... }
private:
float y_;
};
class Funct2 {
public:
Funct2(const std::string& y, int z) : y_(y), z_(z) { }
int operator()(int x) { ...code from funct2... }
private:
std::string y_;
int z_;
};
class Funct3 {
public:
Funct3(const std::vector<double>& y) : y_(y) { }
int operator()(int x) { ...code from funct3... }
private:
std::vector<double> y_;
};
The difference between this approach and the one in the previous FAQ is that
the fuctionoid gets "bound" to the caller at compile-time rather than at run-time.
Think of it as passing in a parameter: if you know at compile-time the kind of
functionoid you ultimately want to pass in, then you can use the above technique,
and you can, at least in typical cases, get a speed benefit from having the
compiler inline-expand the functionoid code within the caller. Here is an example:
When the compiler compiles the above, it might inline-expand the call which
might improve performance.
void blah()
{
...
Funct2 x("functionoids are powerful", 42);
myCode(x);
...
}
Aside: as was hinted at in the first paragraph above, you may also pass in the
names of normal functions (though you might incur the cost of the function call
when the caller uses these):
void blah()
{
...
myCode(myNormalFunction);
...
}
Yep.
Note: if it's a static member function of class Fred, its type is the same as if it
were an ordinary function: "int (*)(char,float)".
Don't.
Here's an example of the worst case (using a global). Suppose you want to call
Fred::memberFn() on interrupt:
class Fred {
public:
void memberFn();
static void staticMemberFn(); // A static member function can usually handl
e it
...
};
void Fred_memberFn_wrapper()
{
object_which_will_handle_signal->memberFn();
}
int main()
{
/* signal(SIGINT, Fred::memberFn); */ // Can NOT do this
signal(SIGINT, Fred_memberFn_wrapper); // OK
signal(SIGINT, Fred::staticMemberFn); // OK usually; see below
...
}
Note: static member functions do not require an actual object to be invoked, so
pointers-to-static-member-functions are usually type-compatible with regular
pointers-to-functions. However, although it probably works on most compilers, it
actually would have to be an extern "C" non-member function to be correct,
since "C linkage" doesn't only cover things like name mangling, but also calling
conventions, which might be different between C and C++.
This is a special case of the previous two questions, therefore read the previous
two answers first.
One possible solution is to use a static member as the interrupt service routine
and have that function look somewhere to find the instance/member pair that
should be called on interrupt. Thus the effect is that a member function is invoked
on an interrupt, but for technical reasons you need to call an intermediate
function first.
Short answer: if you're trying to store it into (or pass it as) a pointer-to-function,
then that's the problem — this is a corollary to the previous FAQ.
Long answer: In C++, member functions have an implicit parameter which points
to the object (the this pointer inside the member function). Normal C functions
can be thought of as having a different calling convention from member
functions, so the types of their pointers (pointer-to-member-function vs. pointer-
to-function) are different and incompatible. C++ introduces a new type of pointer,
called a pointer-to-member, which can be invoked only by providing an object.
class Fred {
public:
int f(char x, float y);
int g(char x, float y);
int h(char x, float y);
int i(char x, float y);
...
};
(Normally I dislike #define macros, but you should use them with pointers to
members because they improve the readability and writability of that sort of
code.)
...
}
Note: #define macros are evil in 4 different ways: evil#1, evil#2, evil#3, and
evil#4. But they're still useful sometimes. But you should still feel a vague sense
of shame after using them.
Use both the typedef and the #define macro described earlier, and you're 90%
done.
class Fred {
public:
int f(char x, float y);
int g(char x, float y);
int h(char x, float y);
int i(char x, float y);
...
};
And your usage of one of the member function pointers is also straightforward:
Note: #define macros are evil in 4 different ways: evil#1, evil#2, evil#3, and
evil#4. But they're still useful sometimes. Feel ashamed, feel guilty, but when an
evil construct like a macro improves your software, use it.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
No!
class Fred {
public:
int f(char x, float y);
int g(char x, float y);
int h(char x, float y);
int i(char x, float y);
...
};
int main()
{
FredMemFn p = &Fred::f;
void* p2 = (void*)p; // ← illegal!!
Fred o;
callit(o, p, 'x', 3.14f); // okay
callit(o, FredMemFn(p2), 'x', 3.14f); // might fail!!
...
}
Please do not email me if the above seems to work on your particular version of
your particular compiler on your particular operating system. I don't care. It's
illegal, period.
No!
typedef int(*FunctPtr)(char,float);
int callit(FunctPtr p, char x, float y)
{
return p(x, y);
}
int main()
{
FunctPtr p = f;
void* p2 = (void*)p; // ← illegal!!
callit(p, 'x', 3.14f); // okay
callit(FunctPtr(p2), 'x', 3.14f); // might fail!!
...
}
Please do not email me if the above seems to work on your particular version of
your particular compiler on your particular operating system. I don't care. It's
illegal, period.
Use a functionoid.
[33.10] What the heck is a functionoid, and why would I use one?
typedef int(*FunctPtr)(...params...);
void myCode(FunctPtr f)
{
...
f(...args-go-here...);
...
}
FunctPtr array[10];
array[0] = funct1;
array[1] = funct1;
array[2] = funct3;
array[3] = funct2;
...
array[i](...args-go-here...);
With functionoids, you first create a base class with a pure-virtual method:
class Funct {
public:
virtual int doit(int x) = 0;
virtual ~Funct() = 0;
};
inline Funct::~Funct() { } // defined even though it's pure virtual; it's faster this way;
trust me
void myCode(FunctPtr f)
{
...
f->doit(...args-go-here...);
...
}
FunctPtr array[10];
array[0] = new Funct1(...ctor-args...);
array[1] = new Funct1(...ctor-args...);
array[2] = new Funct3(...ctor-args...);
array[3] = new Funct2(...ctor-args...);
...
This gives us the first hint about where functionoids are strictly more powerful
than function-pointers: the fact that the functionoid approach has arguments you
can pass to the ctors (shown above as ...ctor-args...) whereas the function-
pointers version does not. Think of a functionoid object as a freeze-dried
function-call (emphasis on the word call). Unlike a pointer to a function, a
functionoid is (conceptually) a pointer to a partially called function. Imagine for
the moment a technology that lets you pass some-but-not-all arguments to a
function, then lets you freeze-dry that (partially completed) call. Pretend that
technology gives you back some sort of magic pointer to that freeze-dried
partially-completed function-call. Then later you pass the remaining args using
that pointer, and the system magically takes your original args (that were freeze-
dried), combines them with any local variables that the function calculated prior
to being freeze-dried, combines all that with the newly passed args, and
continues the function's execution where it left off when it was freeze-dried. That
might sound like science fiction, but it's conceptually what functionoids let you do.
Plus they let you repeatedly "complete" that freeze-dried function-call with
various different "remaining parameters," as often as you like. Plus they allow
(not require) you to change the freeze-dried state when it gets called, meaning
functionoids can remember information from one call to the next.
Okay, let's get our feet back on the ground and we'll work a couple of examples
to explain what all that mumbo jumbo really means.
Suppose the original functions (in the old-fashioned function-pointer style) took
slightly different parameters.
With functionoids, the situation is, at least sometimes, much better. Since a
functionoid can be thought of as a freeze-dried function call, just take the un-
common args, such as the ones I've called y and/or z, and make them args to the
corresponding ctors. You may also pass the common args (in this case the int
called x) to the ctor, but you don't have to — you have the option of passing
it/them to the pure virtual doit() method instead. I'll assume you want to pass x
and into doit() and y and/or z into the ctors:
class Funct {
public:
virtual int doit(int x) = 0;
};
FunctPtr array[10];
std::vector<double> bottlesOfBeerOnTheWall;
bottlesOfBeerOnTheWall.push_back(100);
bottlesOfBeerOnTheWall.push_back(99);
...
bottlesOfBeerOnTheWall.push_back(1);
array[2] = new Funct3(bottlesOfBeerOnTheWall);
...
So when the user invokes the doit() on one of these functionoids, he supplies
the "remaining" args, and the call conceptually combines the original args passed
to the ctor with those passed into the doit() method:
array[i]->doit(12);
As I've already hinted, one of the benefits of functionoids is that you can have
several instances of, say, Funct1 in your array, and those instances can have
different parameters freeze-dried into them. For example, array[0] and array[1]
are both of type Funct1, but the behavior of array[0]->doit(12) will be different
from the behavior of array[1]->doit(12) since the behavior will depend on both
the 12 that was passed to doit() and the args passed to the ctors.
void childRoutine(FunctPtr f)
{
...
f(...args...);
...
}
void yourCaller()
{
...
childRoutine(funct3);
...
}
void childRoutine(Funct& f)
{
...
f.doit(...args...);
...
}
void myCaller()
{
...
Funct1 funct(...ctor-args...);
childRoutine(funct);
...
}
void yourCaller()
{
...
Funct3 funct(...ctor-args...);
childRoutine(funct);
...
}
Given this example as a backdrop, we can see two benefits of functionoids over
function-pointers. The "ctor args" benefit described above, plus the fact that
functionoids can maintain state between calls in a thread-safe manner. With plain
function-pointers, people normally maintain state between calls via static data.
However static data is not intrinsically thread-safe — static data is shared
between all threads. The functionoid approach provides you with something that
is intrinsically thread-safe since the code ends up with thread-local data. The
implementation is trivial: change the old-fashioned static datum to an instance
data member inside the functionoid's this object, and poof, the data is not only
thread-local, but it is even safe with recursive calls: each call to yourCaller() will
have its own distinct Funct3 object with its own distinct instance data.
Note that we've gained something without losing anything. If you want thread-
global data, functionoids can give you that too: just change it from an instance
data member inside the functionoid's this object to a static data member within
the functionoid's class, or even to a local-scope static data. You'd be no better off
than with function-pointers, but you wouldn't be worse off either.
The functionoid approach gives you a third option which is not available with the
old-fashioned approach: the functionoid lets callers decide whether they want
thread-local or thread-global data. They'd be responsible to use locks in cases
where they wanted thread-global data, but at least they'd have the choice. It's
easy:
void callerWithThreadLocalData()
{
...
Funct1 funct(...ctor-args...);
childRoutine(funct);
...
}
void callerWithThreadGlobalData()
{
...
static Funct1 funct(...ctor-args...); ← the static is the only difference
childRoutine(funct);
...
}
Yes.
If you have a small functionoid, and in the real world that's rather common, the
cost of the function-call can be high compared to the cost of the work done by the
functionoid. In the previous FAQ, functionoids were implemented using virtual
functions and will typically cost you a function-call. An alternate approach uses
templates.
The following example is similar in spirit to the one in the previous FAQ. I have
renamed doit() to operator()() to improve the caller code's readability and to
allow someone to pass a regular function-pointer:
class Funct1 {
public:
Funct1(float y) : y_(y) { }
int operator()(int x) { ...code from funct1... }
private:
float y_;
};
class Funct2 {
public:
Funct2(const std::string& y, int z) : y_(y), z_(z) { }
int operator()(int x) { ...code from funct2... }
private:
std::string y_;
int z_;
};
class Funct3 {
public:
Funct3(const std::vector<double>& y) : y_(y) { }
int operator()(int x) { ...code from funct3... }
private:
std::vector<double> y_;
};
The difference between this approach and the one in the previous FAQ is that
the fuctionoid gets "bound" to the caller at compile-time rather than at run-time.
Think of it as passing in a parameter: if you know at compile-time the kind of
functionoid you ultimately want to pass in, then you can use the above technique,
and you can, at least in typical cases, get a speed benefit from having the
compiler inline-expand the functionoid code within the caller. Here is an example:
When the compiler compiles the above, it might inline-expand the call which
might improve performance.
Aside: as was hinted at in the first paragraph above, you may also pass in the
names of normal functions (though you might incur the cost of the function call
when the caller uses these):
void blah()
{
...
myCode(myNormalFunction);
...
}
• [34.1] Why should I use container classes rather than simple arrays?
• [34.2] How can I make a perl-like associative array in C++?
• [34.3] Is the storage for a std::vector<T> guaranteed to be contiguous?
UPDATED!
• [34.4] How can I build a <favorite container> of objects of different types?
• [34.5] How can I insert/access/change elements from a linked
list/hashtable/etc?
Fundamentally it boils down to this simple fact: C++ is not C. That means (this
might be painful for you!!) you'll need to set aside some of your hard earned
wisdom from your vast experience in C. The two languages simply are different.
The "best" way to do something in C is not always the same as the "best" way to
do it in C++. If you really want to program in C, please do yourself a favor and
program in C. But if you want to be really good at C++, then learn the C++ ways
of doing things. You may be a C guru, but if you're just learning C++, you're just
learning C++ — you're a newbie. (Ouch; I know that had to hurt. Sorry.)
1. Subscripts don't get checked to see if they are out of bounds. (Note that
some container classes, such as std::vector, have methods to access
elements with or without bounds checking on subscripts.)
2. Arrays often require you to allocate memory from the heap (see below for
examples), in which case you must manually make sure the allocation is
eventually deleted (even when someone throws an exception). When you
use container classes, this memory management is handled automatically,
but when you use arrays, you have to manually write a bunch of code (and
unfortunately that code is often subtle and tricky) to deal with this. For
example, in addition to writing the code that destroys all the objects and
deletes the memory, arrays often also force you you to write an extra try
block with a catch clause that destroys all the objects, deletes the
memory, then re-throws the exception. This is a real pain in the neck, as
shown here. When using container classes, things are much easier.
3. You can't insert an element into the middle of the array, or even add one
at the end, unless you allocate the array via the heap, and even then you
must allocate a new array and copy the elements.
4. Container classes give you the choice of passing them by reference or by
value, but arrays do not give you that choice: they are always passed by
reference. If you want to simulate pass-by-value with an array, you have to
manually write code that explicitly copies the array's elements (possibly
allocating from the heap), along with code to clean up the copy when
you're done with it. All this is handled automatically for you if you use a
container class.
5. If your function has a non-static local array (i.e., an "auto" array), you
cannot return that array, whereas the same is not true for objects of
container classes.
1. Different C++ containers have different strengths and weaknesses, but for
any given job there's usually one of them that is better — clearer, safer,
easier/cheaper to maintain, and often more efficient — than an array. For
instance,
o You might consider a std::map instead of manually writing code for
a lookup table.
o A std::map might also be used for a sparse array or sparse matrix.
o A std::vector is the most array-like of the standard container
classes, but it also offers various extra features such as bounds
checking via the at() member function, insertions/removals of
elements, automatic memory management even if someone throws
an exception, ability to be passed both by reference and by value,
etc.
o A std::string is almost always better than an array of char (you
can think of a std::string as a "container class" for the sake of
this discussion).
2. Container classes aren't best for everything, and sometimes you may
need to use arrays. But that should be very rare, and if/when it happens:
o Please design your container class's public interface in such a way
that the code that uses the container class is unaware of the fact
that there is an array inside.
o The goal is to "bury" the array inside a container class. In other
words, make sure there is a very small number of lines of code that
directly touch the array (just your own methods of your container
class) so everyone else (the users of your container class) can
write code that doesn't depend on there being an array inside your
container class.
To net this out, arrays really are evil. You may not think so if you're new to C++.
But after you write a big pile of code that uses arrays (especially if you make your
code leak-proof and exception-safe), you'll learn — the hard way. Or you'll learn
the easy way by believing those who've already done things like that. The choice
is yours.
#include <string>
#include <map>
#include <iostream>
int main()
{
// age is a map from string to int
std::map<std::string, int, std::less<std::string> > age;
std::cout << "Fred is " << age["Fred"] << " years old\n";
...
}
Yes.
This means you the following technique is safe:
#include <vector>
#include "Foo.h" /* get class Foo */
void g()
{
std::vector<Foo> v;
...
f(v.empty() ? NULL : &v[0], v.size()); ← safe
}
The funny expression v.empty() ? NULL : &v[0] simply passes the NULL pointer
if v is empty, otherwise passes a pointer to the first (zeroth) element of v. If you
know a priori that v is not empty, you can change that to simply &v[0].
void g()
{
std::vector<Foo> v;
...
f(v.begin(), v.size()); ← Error!! Not Guaranteed!!
^^^^^^^^^-- cough, choke, gag; not guaranteed to be the same as &v[0]
}
Do NOT email me and tell me that v.begin() == &v[0] on your particular version
of your particular compiler on your particular platform. I don't care, plus that
would show that you've totally missed the point. The point is to help you know the
kind of code that is guaranteed to work correctly on all standard-conforming
implementations, not to study the vagaries of particular implementations.
You can't, but you can fake it pretty well. In C/C++ all arrays are homogeneous
(i.e., the elements are all the same type). However, with an extra layer of
indirection you can give the appearance of a heterogeneous container (a
heterogeneous container is a container where the contained objects are of
different types).
The first case occurs when all objects you want to store in a container are
publicly derived from a common base class. You can then declare/define your
container to hold pointers to the base class. You indirectly store a derived class
object in a container by storing the object's address as an element in the
container. You can then access objects in the container indirectly through the
pointers (enjoying polymorphic behavior). If you need to know the exact type of
the object in the container you can use dynamic_cast<> or typeid(). You'll
probably need the Virtual Constructor Idiom to copy a container of disparate
object types. The downside of this approach is that it makes memory
management a little more problematic (who "owns" the pointed-to objects? if you
delete these pointed-to objects when you destroy the container, how can you
guarantee that no one else has a copy of one of these pointers? if you don't
delete these pointed-to objects when you destroy the container, how can you be
sure that someone else will eventually do the deleteing?). It also makes copying
the container more complex (may actually break the container's copying
functions since you don't want to copy the pointers, at least not when the
container "owns" the pointed-to objects).
The second case occurs when the object types are disjoint — they do not share
a common base class. The approach here is to use a handle class. The
container is a container of handle objects (by value or by pointer, your choice; by
value is easier). Each handle object knows how to "hold on to" (i.e., maintain a
pointer to) one of the objects you want to put in the container. You can use either
a single handle class with several different types of pointers as instance data, or
a hierarchy of handle classes that shadow the various types you wish to contain
(requires the container be of handle base class pointers). The downside of this
approach is that it opens up the handle class(es) to maintenance every time you
change the set of types that can be contained. The benefit is that you can use
the handle class(es) to encapsulate most of the ugliness of memory
management and object lifetime. Thus using handle objects may be beneficial
even in the first case.
The most important thing to remember is this: don't roll your own from scratch
unless there is a compelling reason to do so. In other words, instead of creating
your own list or hashtable, use one of the standard class templates such as
std::vector<T> or std::list<T> or whatever.
Assuming you have a compelling reason to build your own container, here's how
to handle inserting (or accessing, changing, etc.) the elements.
To make the discussion concrete, I'll discuss how to insert an element into a
linked list. This example is just complex enough that it generalizes pretty well to
things like vectors, hash tables, binary trees, etc.
A linked list makes it easy insert an element before the first or after the last
element of the list, but limiting ourselves to these would produce a library that is
too weak (a weak library is almost worse than no library). This answer will be a
lot to swallow for novice C++'ers, so I'll give a couple of options. The first option
is easiest; the second and third are better.
1. Empower the List with a "current location," and member functions such
as advance(), backup(), atEnd(), atBegin(), getCurrElem(),
setCurrElem(Elem), insertElem(Elem), and removeElem(). Although this
works in small examples, the notion of a current position makes it difficult
to access elements at two or more positions within the list (e.g., "for all
pairs x,y do the following...").
2. Remove the above member functions from List itself, and move them to a
separate class, ListPosition. ListPosition would act as a "current
position" within a list. This allows multiple positions within the same list.
ListPosition would be a friend of class List, so List can hide its
innards from the outside world (else the innards of List would have to be
publicized via public member functions in List). Note: ListPosition can
use operator overloading for things like advance() and backup(), since
operator overloading is syntactic sugar for normal member functions.
3. Consider the entire iteration as an atomic event, and create a class
template that embodies this event. This enhances performance by
allowing the public access member functions (which may be virtual
functions) to be avoided during the access, and this access often occurs
within an inner loop. Unfortunately the class template will increase the size
of your object code, since templates gain speed by duplicating code. For
more, see [Koenig, "Templates as interfaces," JOOP, 4, 5 (Sept 91)], and
[Stroustrup, "The C++ Programming Language Third Edition," under
"Comparator"].
A template is a cookie-cutter that specifies how to cut cookies that all look pretty
much the same (although the cookies can be made of various kinds of dough,
they'll all have the same basic shape). In the same way, a class template is a
cookie cutter for a description of how to build a family of classes that all look
basically the same, and a function template describes how to build a family of
similar looking functions.
Class templates are often used to build type safe containers (although this only
scratches the surface for how they can be used).
Repeating the above over and over for Array of float, of char, of std::string, of
Array-of-std::string, etc, will become tedious.
int main()
{
Array<int> ai;
Array<float> af;
Array<char*> ac;
Array<std::string> as;
Array< Array<int> > aai;
...
}
Note the space between the two >'s in the last example. Without this space, the
compiler would see a >> (right-shift) token instead of two >'s.
If we also had to swap floats, longs, Strings, Sets, and FileSystems, we'd get
pretty tired of coding lines that look almost identical except for the type. Mindless
repetition is an ideal job for a computer, hence a function template:
template<typename T>
void swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
Every time we used swap() with a given pair of types, the compiler will go to the
above definition and will create yet another "template function" as an instantiation
of the above. E.g.,
int main()
{
int i,j; /*...*/ swap(i,j); // Instantiates a swap for int
float a,b; /*...*/ swap(a,b); // Instantiates a swap for float
char c,d; /*...*/ swap(c,d); // Instantiates a swap for char
std::string s,t; /*...*/ swap(s,t); // Instantiates a swap for std::string
...
}
When you call a function template, the compiler tries to deduce the template
type. Most of the time it can do that successfully, but every once in a while you
may want to help the compiler deduce the right type — either because it cannot
deduce the type at all, or perhaps because it would deduce the wrong type.
For example, you might be calling a function template that doesn't have any
parameters of its template argument types, or you might want to force the
compiler to do certain promotions on the arguments before selecting the correct
function template. In these cases you'll need to explicitly tell the compiler which
instantiation of the function template should be called.
Here is a sample function template where the template parameter T does not
appear in the function's parameter list. In this case the compiler cannot deduce
the template parameter types when the function is called.
template<typename T>
void f()
{
...
}
To call this function with T being an int or a std::string, you could say:
#include <string>
void sample()
{
f<int>(); // type T will be int in this call
f<std::string>(); // type T will be std::string in this call
}
Here is another function whose template parameters appear in the function's list
of formal parameters (that is, the compiler can deduce the template type from the
actual arguments):
template<typename T>
void g(T x)
{
...
}
Now if you want to force the actual arguments to be promoted before the
compiler deduces the template type, you can use the above technique. E.g., if
you simply called g(42) you would get g<int>(42), but if you wanted to pass 42
to g<long>(), you could say this: g<long>(42). (Of course you could also
promote the parameter explicitly, such as either g(long(42)) or even g(42L), but
that ruins the example.)
Similarly if you said g("xyz") you'd end up calling g<char*>(char*), but if you
wanted to call the std::string version of g<>() you could say
g<std::string>("xyz"). (Again you could also promote the argument, such as
g(std::string("xyz")), but that's another story.)
Before showing how to do this, let's make sure you're not shooting yourself in the
foot. Does the function's behavior appear different to your users? In other words,
is the observable behavior different in some substantive way? If so, you're
probably shooting yourself in the foot and you will probably confuse your users —
you're probably better off using different functions with different names — don't
use templates, don't use overloading. For example, if the code for int inserts
something into a container and sorts the result, but the code for std::string
removes something from a container and does not sort the result, those two
functions ought not to be an overloaded pair — their observable behavior is
different so they ought to have different names.
However if the function's observable behavior is consistent for all the T types with
the differences limited to implementation details, then you can proceed. Let's
proceed with an example of this (conceptual only; not C++):
template<typename T>
void foo(const T& x)
{
switch (typeof(T)) { ← conceptual only; not C++
case int:
... ← implementation details when T is int
break;
case std::string:
... ← implementation details when T is std::string
break;
default:
... ← implementation details when T is neither int nor std::string
break;
}
}
Next are the two specializations, first for the int case...
template<>
void foo<int>(const int& x)
{
... ← implementation details when T is int
}
template<>
void foo<std::string>(const std::string& x)
{
... ← implementation details when T is std::string
}
That's it; you're done. The compiler will automagically select the correct
specialization when it sees which T you are using.
Yes.
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
#include <limits>
Conceptually they all do the same thing: stringify the parameter. That means the
observable behavior is consistent, therefore the specializations do not confuse
callers. However the details for implementing that observable behavior is slightly
different for bool and floating point types, so template specialization is a good
approach.
Yes.
For example, suppose your template function has a bunch of common code
along with a relatively small amount of T-specific code (conceptual only; not C+
+):
template<typename T>
void foo(const T& x)
{
... common code that works for all T types ...
case std::string:
... small amount of code used only when T is std::string ...
break;
default:
... small amount of code used when T is neither int nor std::string ...
break;
}
... more common code that works for all T types ...
}
If you blindly applied the advice from the FAQ on template specialization, you
would end up duplicating all that code before and after the pseudo-switch
statement. The way to get the best of both worlds — to get the benefits of T-
specific pieces without duplicating the entire function, is to extract the pseudo-
switch statement portion into a separate function foo_part(), and use template
specialization on that separate function:
template<typename T>
void foo(const T& x)
{
... common code that works for all T types ...
foo_part(x);
... more common code that works for all T types ...
}
As you can see, the body of foo() now doesn't mention any particular T. It all
gets figured out automatically. The compiler generates foo for you based on type
T, and will generate the correctly typed foo_part function based on the actual
compile-time known type of the x argument. Proper specializations of foo_part
will be instantiated.
Wrong.
#include <iostream>
#include <typeinfo>
void foo(int x)
{ std::cout << "foo(int)\n"; }
void foo(double x)
{ std::cout << "foo(double)\n"; }
int main()
{
foo(42); // matches foo(int) exactly
foo(42.0); // matches foo(double) exactly
foo("abcdef"); // matches foo<T>(T*) with T = char
return 0;
}
In this example, foo<T> cannot be considered for the first or the second call to
foo in the body of main because neither 42 nor 42.0 gives the compiler any
information to deduce T. The third call, however, includes foo<T> with T = char
and it wins.
If all you want to know is how to fix this situation, read the next two FAQs. But in
order to understand why things are the way they are, first accept these facts:
template<typename T>
class Foo {
public:
Foo();
void someMethod(T x);
private:
T x;
};
template<typename T>
Foo<T>::Foo()
{
...
}
template<typename T>
void Foo<T>::someMethod(T x)
{
...
}
Now suppose you have some code in file Bar.cpp that uses Foo<int>:
// Bar.cpp
void blah_blah_blah()
{
...
Foo<int> f;
f.someMethod(5);
...
}
Clearly somebody somewhere is going to have to use the "pattern" for the
constructor definition and for the someMethod() definition and instantiate those
when T is actually int. But if you had put the definition of the constructor and
someMethod() into file Foo.cpp, the compiler would see the template code when it
compiled Foo.cpp and it would see Foo<int> when it compiled Bar.cpp, but there
would never be a time when it saw both the template code and Foo<int>. So by
rule #2 above, it could never generate the code for Foo<int>::someMethod().
A note to the experts: I have obviously made several simplifications above. This
was intentional so please don't complain too loudly. If you know the difference
between a .cpp file and a compilation unit, the difference between a class
template and a template class, and the fact that templates really aren't just
glorified macros, then don't complain: this particular question/answer wasn't
aimed at you to begin with. I simplified things so newbies would "get it," even if
doing so offends some experts.
Reminder: Read the next two FAQs for some solutions to this problem.
Tell your C++ compiler which instantiations to make while it is compiling your
template function's .cpp file.
As an example, consider the header file foo.h which contains the following
template function declaration:
// File "foo.h"
template<typename T>
extern void foo();
// File "foo.cpp"
#include <iostream>
#include "foo.h"
template<typename T>
void foo()
{
std::cout << "Here I am!\n";
}
// File "main.cpp"
#include "foo.h"
int main()
{
foo<int>();
...
}
If you compile and (try to) link these two .cpp files, most compilers will generate
linker errors. There are three solutions for this. The first solution is to physically
move the definition of the template function into the .h file, even if it is not an
inline function. This solution may (or may not!) cause significant code bloat,
meaning your executable size may increase dramatically (or, if your compiler is
smart enough, may not; try it and see).
The other solution is to leave the definition of the template function in the .cpp file
and simply add the line template void foo<int>(); to that file:
// File "foo.cpp"
#include <iostream>
#include "foo.h"
If you can't modify foo.cpp, simply create a new .cpp file such as foo-impl.cpp
as follows:
// File "foo-impl.cpp"
#include "foo.cpp"
Notice that foo-impl.cpp #includes a .cpp file, not a .h file. If that's confusing,
click your heels twice, think of Kansas, and repeat after me, "I will do it anyway
even though it's confusing." You can trust me on this one. But if you don't trust
me or are simply curious, the rationale is given earlier.
[35.14] How does the C++ keyword export help with template linker
errors? UPDATED!
[Recently fixed a bug in the last paragraph by changing NO_EXPORT_KEYWORD to
USE_EXPORT_KEYWORD thanks to Luís Bruno (in 9/06). Click here to go to the next FAQ in the
"chain" of recent changes.]
The C++ keyword export is designed to eliminate the need to include a template
definition (either by providing the definition in the header file or by including the
implementation file). However, at the time of this writing, the only well-known
compiler that supports this capability is Comeau C++. The future of the export
keyword is unknown. Without taking sides in the debate, I will simply report that
some compiler vendors are indicating they might never implement it, and that the
C++ standards committee has decided to leave it in.
If you want your code to work with compilers that do not support the export
keyword, yet to also take advantage of the export keyword with compilers that
support it, define your template header-files like this:
// File Foo.h
template<typename T>
class Foo {
...
};
#ifndef USE_EXPORT_KEYWORD
#include "Foo.cpp"
#endif
// File Foo.cpp
#ifndef USE_EXPORT_KEYWORD
#define export /*nothing*/
#endif
Then, if/when your compiler supports the export keyword, and if for whatever
reason you want to exploit that feature, just define the symbol
USE_EXPORT_KEYWORD.
The point is that you can program today as if your compiler has the export
keyword, and if/when your compiler actually does support that keyword, define
the USE_EXPORT_KEYWORD symbol, recompile, and you will be exploiting that
feature.
Tell your C++ compiler which instantiations to make while it is compiling your
template class's .cpp file.
(If you've already read the previous FAQ, this answer is completely symmetric
with that one, so you can probably skip this answer.)
As an example, consider the header file Foo.h which contains the following
template class. Note that method Foo<T>::f() is inline and methods Foo<T>::g()
and Foo<T>::h() are not.
// File "Foo.h"
template<typename T>
class Foo {
public:
void f();
void g();
void h();
};
template<typename T>
inline
void Foo<T>::f()
{
...
}
Now suppose file Foo.cpp actually defines the non-inline methods Foo<T>::g()
and Foo<T>::h():
// File "Foo.cpp"
#include <iostream>
#include "Foo.h"
template<typename T>
void Foo<T>::g()
{
std::cout << "Foo<T>::g()\n";
}
template<typename T>
void Foo<T>::h()
{
std::cout << "Foo<T>::h()\n";
}
Suppose file main.cpp uses this template class by creating a Foo<int> and
calling its methods:
// File "main.cpp"
#include "Foo.h"
int main()
{
Foo<int> x;
x.f();
x.g();
x.h();
...
}
If you compile and (try to) link these two .cpp files, most compilers will generate
linker errors. There are three solutions for this. The first solution is to physically
move the definition of the template functions into the .h file, even if they are not
inline functions. This solution may (or may not!) cause significant code bloat,
meaning your executable size may increase dramatically (or, if your compiler is
smart enough, may not; try it and see).
The other solution is to leave the definition of the template function in the .cpp file
and simply add the line template class Foo<int>; to that file:
// File "Foo.cpp"
#include <iostream>
#include "Foo.h"
If you can't modify Foo.cpp, simply create a new .cpp file such as Foo-impl.cpp
as follows:
// File "Foo-impl.cpp"
#include "Foo.cpp"
Notice that Foo-impl.cpp #includes a .cpp file, not a .h file. If that's confusing,
click your heels twice, think of Kansas, and repeat after me, "I will do it anyway
even though it's confusing." You can trust me on this one. But if you don't trust
me or are simply curious, the rationale is given earlier.
If you are using Comeau C++, you probably want to check out the export
keyword.
Ah, the intricacies of template friends. Here's an example of what people often
want to do:
#include <iostream>
template<typename T>
class Foo {
public:
Foo(const T& value = T());
friend Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs);
friend std::ostream& operator<< (std::ostream& o, const Foo<T>& x);
private:
T value_;
};
And of course the various member and friend functions will need to be defined
somewhere:
template<typename T>
Foo<T>::Foo(const T& value = T())
: value_(value)
{ }
template<typename T>
Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs)
{ return Foo<T>(lhs.value_ + rhs.value_); }
template<typename T>
std::ostream& operator<< (std::ostream& o, const Foo<T>& x)
{ return o << x.value_; }
The snag happens when the compiler sees the friend lines way up in the class
definition proper. At that moment it does not yet know the friend functions are
themselves templates; it assumes they are non-templates like this:
When you call the operator+ or operator<< functions, this assumption causes
the compiler to generate a call to the non-template functions, but the linker will
give you an "undefined external" error because you never actually defined those
non-template functions.
The solution is to convince the compiler while it is examining the class body
proper that the operator+ and operator<< functions are themselves templates.
There are several ways to do this; one simple approach is pre-declare each
template friend function above the definition of template class Foo:
#include <iostream>
template<typename T>
class Foo {
public:
Foo(const T& value = T());
friend Foo<T> operator+ <> (const Foo<T>& lhs, const Foo<T>& rhs);
friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x
);
private:
T value_;
};
After the compiler sees that magic stuff, it will be better informed about the
friend functions. In particular, it will realize that the friend lines are referring to
functions that are themselves templates. That eliminates the confusion.
Another approach is to define the friend function within the class body at the
same moment you declare it to be a friend. For example:
#include <iostream>
template<typename T>
class Foo {
public:
Foo(const T& value = T());
private:
T value_;
};
Here's a free tool that transforms error messages into something more
understandable. At the time of this writing, it works with the following compilers:
Comeau C++, Intel C++, CodeWarrior C++, gcc, Borland C++, Microsoft Visual
C++, and EDG C++.
Here's what the filtered error messages look like (note: you can configure the tool
so it shows more information; this output was generated with settings to strip
things down to a minimum):
#include <map>
#include <algorithm>
#include <cmath>
int main()
{
using namespace std;
valmap m;
return 0;
}
[Recently created thanks to Victor Bazarov (in 9/06). Click here to go to the next FAQ in the
"chain" of recent changes.]
Perhaps surprisingly, the following code is not valid C++, even though some
compilers accept it:
template<typename T>
class B {
public:
class Xyz { ... }; ← type nested in class B<T>
typedef int Pqr; ← type nested in class B<T>
};
template<typename T>
class D : public B<T> {
public:
void g()
{
Xyz x; ← bad (even though some compilers erroneously (temporarily?) accept it)
Pqr y; ← bad (even though some compilers erroneously (temporarily?) accept it)
}
};
Within D<T>::g(), name Xyz and Pqr do not depend on template parameter T, so
they are known as a nondependent names. On the other hand, B<T> is
dependent on template parameter T so B<T> is called a dependent name.
Here's the rule: the compiler does not look in dependent base classes (like B<T>)
when looking up nondependent names (like Xyz or Pqr). As a result, the compiler
does not know they even exist let alone are types.
At this point, programmers sometimes prefix them with B<T>::, such as:
template<typename T>
class D : public B<T> {
public:
void g()
{
B<T>::Xyz x; ← bad (even though some compilers erroneously (temporarily?) accep
t it)
B<T>::Pqr y; ← bad (even though some compilers erroneously (temporarily?) accep
t it)
}
};
Unfortunately this doesn't work either because those names (are you ready? are
you sitting down?) are not necessarily types. "Huh?!?" you say. "Not types?!?"
you exclaim. "That's crazy; any fool can SEE they are types; just look!!!" you
protest. Sorry, the fact is that they might not be types. The reason is that there
can be a specialization of B<T>, say B<Foo>, where B<Foo>::Xyz is a data
member, for example. Because of this potential specialization, the compiler
cannot assume that B<T>::Xyz is a type until it knows T. The solution is to give
the compiler a hint via the typename keyword:
template<typename T>
class D : public B<T> {
public:
void g()
{
typename B<T>::Xyz x; ← good
typename B<T>::Pqr y; ← good
}
};
[Recently wordsmithed, clarified (in 9/06). Click here to go to the next FAQ in the "chain" of recent
changes.]
Perhaps surprisingly, the following code is not valid C++, even though some
compilers accept it:
template<typename T>
class B {
public:
void f() { } ← member of class B<T>
};
template<typename T>
class D : public B<T> {
public:
void g()
{
f(); ← bad (even though some compilers erroneously (temporarily?) accept it)
}
};
Here's the rule: the compiler does not look in dependent base classes (like B<T>)
when looking up nondependent names (like f).
This doesn't mean that inheritance doesn't work. Class D<int> is still derived
from class B<int>, the compiler still lets you implicitly do the is-a conversions
(e.g., D<int>* to B<int>*), dynamic binding still works when virtual functions are
invoked, etc. But there is an issue about how names are looked up.
Workarounds:
• Change the call from f() to this->f(). Since this is always implicitly
dependent in a template, this->f is dependent and the lookup is therefore
deferred until the template is actually instantiated, at which point all base
classes are considered.
• Insert using B<T>::f; just prior to calling f().
• Change the call from f() to B<T>::f(). Note however that this might not
give you what you want if f() is virtual, since it inhibits the virtual dispatch
mechanism.
Yes.
Since non-dependent types and non-dependent members are not found in the
dependent template base-classes, the compiler will search the enclosing scope,
such as the enclosing namespace. This can cause it to silently(!) do the wrong
thing.
For example:
template<typename T>
class D : public B<T> {
public:
void g()
{
Xyz x; ← suprise: you get the global Xyz!!
f(); ← suprise: you get the global f!!
}
};
The use of Xyz and f within D<T>::g() will silently(!) resolve to the global entities
rather than those inherited from class B<T>.
It lets you take an object or group of objects, put them on a disk or send them
through a wire or wireless transport mechanism, then later, perhaps on another
computer, reverse the process: resurrect the original object(s). The basic
mechanisms are to flatten object(s) into a one-dimensional stream of bits, and to
turn that stream of bits back into the original object(s).
Like the Transporter on Star Trek, it's all about taking something complicated and
turning it into a flat sequence of 1s and 0s, then taking that sequence of 1s and
0s (possibly at another place, possibly at another time) and reconstructing the
original complicated "something."
There are lots and lots (and lots) of if's, and's and but's, and in reality there are a
whole continuum of techniques with lots of dimensions. Because I have a finite
amount of time (translation: I don't get paid for any of this), I've simplified it to a
decision between using human-readable ("text") or non-human-readable
("binary") format, followed by a list of five techniques arranged more-or-less in
increasing order of sophistication.
You are, of course, not limited to those five techniques. You will probably end up
mixing ideas from several techniques. And certainly you can always use a more
sophisticated (higher numbered) technique than is actually needed. In fact it
might be wise to use a more sophisticated technique than is minimally needed if
you believe future changes will require the greater sophistication. So think of this
list merely as a good starting point.
1. The first step is to make an eyes-open decision between text- and binary-
formats.
2. If your objects aren't part of an inheritance hierarchy and don't contain
pointers, use solution #1.
3. Else if your objects don't contain pointers to other objects, use solution #2.
4. Else if the graph of pointers within your objects contain neither cycles nor
joins, use solution #3.
5. Else if the graph of pointers within your objects don't contain cycles and if
the only joins are to terminal (leaf) nodes, use solution #4.
6. Else use solution #5.
Remember: feel free to mix and match, to add to the above list, and, if you can
justify the added expense, to use a more sophisticated technique than is
minimally required.
One more thing: the issues of inheritance and of pointers within the objects are
logically unrelated, so there's no theoretical reason for #2 to be any less
sophisticated than #3-5. However in practice it often (not always) works out that
way. So please do not think of these categories as somehow sacred — they're
somewhat arbitrary, and you are expected to mix and match the solutions to fit
your situation. This whole area of serialization has far more variants and shades
of gray than can be covered in a few questions/answers.
Carefully.
There is no "right" answer to this question; it really depends on your goals. Here
are a few of the pros/cons of human-readable ("text") format vs. non-human-
readable ("binary") format:
• Text format is easier to "desk check." That means you won't have to write
extra tools to debug the input and output; you can open the serialized
output with a text editor to see if it looks right.
• Binary format typically uses fewer CPU cycles. However that is relevant
only if your application is CPU bound and you intend to do serialization
and/or unserialization on an inner loop/bottleneck. Remember: 90% of the
CPU time is spent in 10% of the code, which means there won't be any
practical performance benefit unless your "CPU meter" is pegged at
100%, and your serialization and/or unserialization code is consuming a
healthy portion of that 100%.
• Text format lets you ignore programming issues like sizeof and little-
endian vs. big-endian.
• Binary format lets you ignore separations between adjacent values, since
many values have fixed lengths.
• Text format can produce smaller results when most numbers are small
and when you need to textually encode binary results, e.g., uuencode or
Base64.
• Binary format can produce smaller results when most numbers are large
or when you don't need to textually encode binary results.
You might think of others to add as well... The important thing to remember is
that one size does not fit all — make a careful decision here.
One more thing: no matter which you choose, you might want to start each file /
stream with a "magic" tag and a version number. The version number would
indicate the format rules. That way if you decide to make a radical change in the
format, you hopefully will still be able to read the output produced by the old
software.
The primitives discussed in those FAQs will be needed for most of the other
FAQs in this section.
Before you read this, make sure to evaluate all the tradeoffs between human-
readable and non-human-readable formats. The tradeoffs are non-trivial, so you
should resist a knee-jerk reaction to do it the way you did it on the last project —
one size does not fit all.
• You probably want to use iostream's >> and << operators rather than its
read() and write() methods. The >> and << operators are better for text
mode, whereas read() and write() are better for binary mode.
• When storing numbers, you'll probably want to add a separator to prevent
items from running together. One simple approach is to always add a
space (' ') before each number, that way the number 1 followed by the
number 2 won't run together and look like a 12. Since the leading space
will automatically get soaked up by the >> operator, you won't have to do
anything explicit to extract the leading space in the code that reads things
back in.
• String data is tricky because you have to unambiguously know when the
string's body stops. You can't unambiguously terminate all strings with a
'\n' or '"' or even '\0' if some string might contain those characters.
You might want to use C++ source-code escape-sequences, e.g., writing
'\' followed by 'n' when you see a newline, etc. After this transformation,
you can either make strings go until end-of-line (meaning they are
deliminated by '\n') or you can delimit them with '"'.
• If you use C++-like escape-sequences for your string data, be sure to
always use the same number of hex digits after '\x' and '\u'. I typically
use 2 and 4 digits respectively. Reason: if you write a smaller number of
hex digits, e.g., if you simply use stream << "\\x" << hex <<
unsigned(theChar), you'll get errors when the next character in the string
happens to be a hex digit. E.g., if the string contains '\xF' followed by
'A', you should write "\x0FA", not "\xFA".
• If you don't use some sort of escape sequence for characters like '\n', be
careful that the operating system doesn't mess up your string data. In
particular, if you open a std::fstream without std::ios::binary, some
operating systems translate end-of-line characters.
• Another approach for string data is to prefix the string's data with an
integer length, e.g., to write "now is the time" as 15:now is the time.
Note that this can make it hard for people to read/write the file, since the
value just after that might not have a visible separator, but you still might
find it useful.
Please remember that these are primitives that you will need to use in the other
FAQs in this section.
Before you read this, make sure to evaluate all the tradeoffs between human-
readable and non-human-readable formats. The tradeoffs are non-trivial, so you
should resist a knee-jerk reaction to do it the way you did it on the last project —
one size does not fit all.
• Make sure you open the input and output streams using
std::ios::binary. Do this even if you are on a Unix system since it's easy
to do, it documents your intent, and it's one less non-portability to locate
and change down the road.
• You probably want to use iostream's read() and write() methods instead
of its >> and << operators. read() and write() are better for binary mode;
>> and << are better for text mode.
• If the binary data might get read by a different computer than the one that
wrote it, be very careful about endian issues (little-endian vs. big-endian)
and sizeof issues. The easiest way to handle this is to anoint one of those
two formats as the official "network" format, and to create a header file
that contains machine dependencies (I usually call it machine.h). That
header should define inline functions like readNetworkInt(std::istream&
istr) to read a "network int," and so forth for reading and writing all the
primitive types. You can define the format for these pretty much anyway
you want. E.g., you might define a "network int" as exactly 32 bits in little
endian format. In any case, the functions in machine.h will do any
necessary endian conversions, sizeof conversions, etc. You'll either end
up with a different machine.h on each machine architecture, or you'll end
up with a lot of #ifdefs in your machine.h, but either way, all this ugliness
will be buried in a single header, and all the rest of your code will be
clean(er). Note: the floating point differences are the most subtle and
tricky to handle. It can be done, but you'll have to be careful with things
like NaN, over- and under-flow, #bits in the mantissa or exponent, etc.
• When space-cost is an issue, such as when you are storing the serialized
form in a small memory device or sending it over a slow link, you can
compress the stream and/or you can do some manual tricks. The simplest
is to store small numbers in a smaller number of bytes. For example, to
store an unsigned integer in a stream that has 8-bit bytes, you can hijack
the 8th bit of each byte to indicate whether or not there is another byte.
That means you get 7 meaningful bits/byte, so 0...127 fit in 1 byte,
128...16384 fit in 2 bytes, etc. If the average number is smaller than
around half a billion, this will use less space than storing every four-byte
unsigned number in four 8-bit bytes. There are lots of other variations on
this theme, e.g., a sorted array of numbers can store the difference
between each number, storing extremely small values in unary format, etc.
• String data is tricky because you have to unambiguously know when the
string's body stops. You can't unambiguously terminate all strings with a
'\0' if some string might contain that character; recall that std::string
can store '\0'. The easiest solution is to write the integer length just
before the string data. Make sure the integer length is written in "network
format" to avoid sizeof and endian problems (see the solutions in earlier
bullets).
Please remember that these are primitives that you will need to use in the other
FAQs in this section.
This is the least sophisticated problem, and not surprisingly, it is also the least
sophisticated solution:
• Every class should handle its own serialization and unserialization. You
will typically create a member function that serializes the object to some
sink (such as a std::ostream), and another that allocates a new object, or
perhaps changes an existing object, setting the member data based on
what it reads from some source (such as a std::istream).
• If your object physically contains another object, e.g., a Car object might
have a member variable of type Engine, the outer object's serialize()
member function should simply call the appropriate function associated
with the member object.
• Use the primitives described earlier to read/write the simple types in text
or binary format.
• If a class's data structure might change someday, the class should write
out a version number at the beginning of the object's serialized output.
The version number simply represents the serialized format; it should not
get incremented simply when the class's behavior changes. This means
the version numbers don't need to be fancy — they usually don't need a
major and minor number.
Suppose you want to serialize a "shape" object, where Shape is an abstract class
with derived classes Rectangle, Ellipse, Line, Text, etc. You would declare a
pure virtual function serialize(std::ostream&) const within class Shape, and
make sure the first thing done by each override is to write out the class's identity.
For example, Ellipse::serialize(std::ostream&) const would write out the
identifier Ellipse (perhaps as a simple string, but there are several alternatives
discussed below).
Things get a little trickier when unserializing the object. You typically start with a
static member function in the base class such as
Shape::unserialize(std::istream& istr). This is declared to return a Shape* or
perhaps a smart pointer such as Shape::Ptr. It reads the class-name identifier,
then uses some sort of creational pattern to create the object. For example, you
might have a table that maps from the class name to an object of the class, then
use the Virtual Constructor Idiom to create the object.
Before we even start, you must understand that the word "tree" does not mean
that the objects are stored in some sort of tree-like data structure. It simply
means that your objects point to each other, and the "with no cycles" part means
if you keep following pointers from one object to the next, you never return to an
earlier object. Your objects aren't "inside" a tree; they are a tree. If you don't
understand that, you really should read the lingo FAQ before continuing with this
one.
Second, don't use this technique if the graph might someday contain cycles or
joins.
Graphs with neither cycles nor joins are very common, even with "recursive
composition" design patterns like Composite or Decorator. For example, the
objects representing an XML document or an HTML document can be
represented as a graph without joins or cycles.
The key to serializing these graphs is to ignore a node's identity and instead to
focus only on its contents. A (typically recursive) algorithm dives through the tree
and writes the contents as it goes. For example, if the current node happens to
have an integer a, a pointer b, a float c, and another pointer d, then you first write
the integer a, then recursively dive into the child pointed to by b, then write the
float c, and finally recursively dive into the child pointed to by d. (You don't have
to write/read them in the declaration order; the only essential rule is that the
reader's order is consistent with the writer's order.)
It is often convenient to use the Named Constructor Idiom when allocating these
objects. This has the advantage that you can enforce the use of smart pointers.
To do this in a class Foo, write a static method such as FooPtr
Foo::create(std::istream& istr) { return new Foo(istr); } (where FooPtr is
a smart pointer to a Foo). The alert reader will note how consistent this is with the
technique discussed in the previous FAQ — the two techniques are completely
compatible.
If a child-pointer might be NULL, be sure to handle that in both the writing and
reading. This shouldn't be a problem if your objects use inheritance; see that
solution for details. Otherwise, if the first serialized character in an object has a
known range, use something outside that range. E.g., if the first character of a
serialized object is always a digit, use a non-digit like 'N' to mean a NULL pointer.
Unseralization can use std::istream::peek() to check for the 'N' tag. If the first
character doesn't have a known range, force one; e.g., write 'x' before each
object, then use something else like 'y' to mean NULL.
As before, the word "tree" does not mean that the objects are stored in some sort
of tree-like data structure. It simply means your objects have pointers to each
other, and the "no cycles" part means you can follow the pointers from one object
to the next and never return to an earlier object. The objects are not "inside" a
tree; they are a tree. If that's doesn't make sense, you really should read the
lingo FAQ before continuing with this one.
Use this solution if the graph contains joins at the leaf nodes, but those joins can
be easily reconstructed via a simple look-up table. For example, the parse-tree of
an arithmetic expression like (3*(a+b) - 1/a) might have joins since a variable-
name (like a) can show up more than once. If you want the graph to use the
same exact node-object to represent both occurrences of that variable, then you
could use this solution.
Although the above constraints don't fit with those of the solution without any
joins, it's so close that you can squeeze things into that solution. Here are the
differences:
Caveat: this assumes that all occurrences of variable a should map to the same
node object; if it's more complicated than this, that is, if some occurrences of a
should map to one object and some to another, you might need to use a more
sophisticated solution.
Caveat: the word "graph" does not mean that the objects are stored in some sort
of data structure. Your objects form a graph because they point to each other.
They're not "inside" a graph; they are a graph. If that doesn't make sense, you
really should read the lingo FAQ before continuing with this one.
Use this solution if the graph can contain cycles, or if it can contain more
complicated kinds of joins than are allowed by the solution for trivial joins. This
solution handles two core issues: it avoids infinite recursion and it writes/reads
each node's identity in addition its contents.
There are some clever ways to serialize the graph, but the simplest to describe is
a two-pass algorithm that uses an object-ID map, e.g.,
std::map<Node*,unsigned> oidMap. The first pass populates our oidMap, that is, it
builds a mapping from object pointer to the integer that represents the object's
identity. It does this by recursively diving through the graph, at each node
checking if the node is already in oidMap, and if not, adding the node and a
unique integer to oidMap and recursively diving into the new node's children. The
unique integer is often just the initial oidMap.size(), e.g., unsigned n =
oidMap.size(); oidMap[nodePtr] = n. (Yes, we did that in two statements. You
must also. Do not shorten it to a single statement. You have been warned.)
The second pass iterates through the nodes of oidMap, and at each, writes the
node's identity (the associated integer) followed by its contents. When writing the
contents of a node that contains pointers to other nodes, instead of diving into
those "child" objects, it simply writes the identity (the associated integer) of the
pointer to those nodes. For example, when your node contains Node* child,
simply write the integer oidMap[child]. After the second pass, the oidMap can be
discarded. In other words, the mapping from Node* to unsigned should not
normally survive beyond the end of the serialization of any given graph.
There are also some clever ways to unserialize the graph, but here again the
simplest to describe is a two-pass algorithm. The first pass populates a
std::vector<Node*> v with objects of the right class, but any child pointers within
those objects are all NULL. This means v[3] will point to the object whose oid is 3,
but any child pointers inside that object will be NULL. The second pass populates
the child pointers inside the objects, e.g., if v[3] has a child pointer called child
that is supposed to point to the object whose oid is 5, the second pass changes
changes v[3].child from NULL to v[5] (obviously encapsulation might prevent it
from directly accessing v[3].child, but ultimately v[3].child gets changed to
v[5]). After unserializing a given stream, the vector v can normally be discarded.
In other words, the oids (3, 5, etc.) mean nothing when serializing or unserializing
a different stream — those numbers are only meaningful within a given stream.
Note: if your objects contain polymorphic pointers, that is, base class pointers
that might point at derived class objects, then use the technique described
earlier. You'll also want to read some of the earlier techniques for handling NULL,
writing version numbers, etc.
Note: you should seriously consider the Visitor pattern when recursively diving
through the graph, since serialization is probably just one of many different
reasons to make that recursive dive, and they'll all need to avoid infinite
recursion.
There's lots more I could say, such as several simplifications and special cases,
but I've already spent too much time on this. If you want more info, spend some
money.
[36.13] What's all this about graphs, trees, nodes, cycles, joins,
and joins at the leaves vs. internal nodes?
When your objects contain pointers to other objects, you end up with something
computer scientists call a graph. Not that your objects are stored inside a tree-
like data structure; they are a tree-like structure.
Your objects correspond to the graph's nodes AKA vertices, and the pointers
within your objects correspond to the graph's edges. The graph is of a special
variety called a rooted, directed graph. The root object to be serialized
corresponds to the graph's root node, and the pointers correspond to directed
edges.
A cycle in a graph means there is a path from an object back to itself: if x has a
pointer to itself, or to y which points to x, or to y which points to z which points to
x, etc. A graph is cyclic if it has one or more cycles; otherwise it is acyclic.
An internal node is a node with children. A leaf node is a node without children.
As used in this section, the word tree means a rooted, directed, acyclic graph.
Note that each node within a tree is also a tree.
Technically speaking the term "STL" is no longer meaningful since the classes
provided by the STL have been fully integrated into the standard library, along
with other standard classes like std::ostream, etc. Nonetheless many people still
refer to the STL as if it were a separate thing, so you might as well get used to
hearing that term.
Since the classes that were part of the STL have become part of the standard
library, your compiler should provide these classes. If your compiler doesn't
include these standard classes, either get an updated version of your compiler or
download a copy of the STL classes from one of the following:
STL hacks for GCC-2.6.3 are part of the GNU libg++ package 2.6.2.1 or later
(and they may be in an earlier version as well). Thanks to Mike Lindner.
Also you may as well get used to some people using "STL" to include the
standard string header, "<string>", and others objecting to that usage.
[37.3] How can I find a Fred object in an STL container of Fred* such
as std::vector<Fred*>?
template<typename T>
class DereferencedEqual {
public:
DereferencedEqual(const T* p) : p_(p) { }
bool operator() (const T* p2) const { return *p_ == *p2; }
private:
const T* p_;
};
Now you can use this template to find an appropriate Fred object:
[37.5] How can you tell if you have a dynamically typed C++ class
library?
• Hint #1: when everything is derived from a single root class, usually
Object.
• Hint #2: when the container classes (List, Stack, Set, etc) are non-
templates.
• Hint #3: when the container classes (List, Stack, Set, etc) insert/extract
elements as pointers to Object. This lets you put an Apple into such a
container, but when you get it out, the compiler knows only that it is
derived from Object, so you have to use a pointer cast to convert it back
to an Apple*; and you'd better pray a lot that it really is an Apple, cause
your blood is on your own head).
You can make the pointer cast "safe" by using dynamic_cast, but this dynamic
testing is just that: dynamic. This coding style is the essence of dynamic typing in
C++. You call a function that says "convert this Object into an Apple or give me
NULL if its not an Apple," and you've got dynamic typing: you don't know what will
happen until run-time.
When you use templates to implement your containers, the C++ compiler can
statically validate 90+% of an application's typing information (the figure "90+%"
is apocryphal; some claim they always get 100%, those who need persistence
get something less than 100% static type checking). The point is: C++ gets
genericity from templates, not from inheritance.
This software is sold and therefore it would be illegal to provide it on the net.
However, it's only about $30.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Many people are surprised by how big executables are, especially if the source
code is trivial. For example, a simple "hello world" program can generate an
executable that is larger than most people expect (40+K bytes).
One reason executables can be large is that portions of the C++ runtime library
might get statically linked with your program. How much gets linked in depends
on compiler options regarding whether to statically or dynamically link the
standard libraries, on how much of it you are using, and on how the implementer
split up the library into pieces. For example, the <iostream> library is quite large,
and consists of numerous classes and virtual functions. Using any part of it
might pull in nearly all of the <iostream> code as a result of the
interdependencies (however there might be a compiler option to dynamically link
these classes, in which case your program might be small).
You have to consult your compiler manuals or the vendor's technical support for
a more detailed answer.
[37.9] Where can I get tons and tons of more information on C++
class libraries?
• The C++ Libraries FAQ is maintained by Nikki Locke and is available with
frames and without frames.
• Also you should check out www.mathtools.net/C_C__/. They have a good
pile of stuff organized into (at present) sixty-some categories.
• Also you should check out www.boost.org/. They have some wonderful
stuff, some of which will get proposed for standardization the next time
around.
Important: none of these lists are exhaustive. If you are looking for some
particular functionality that you don't find above, try a Web search such as
Google. Also, don't forget to help out the next person via the Submission Form in
the C++ Libraries FAQ.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[Recently added the compilers.net site thanks to Dejan Milicic plus added Microsoft's command-
line compiler (in 3/06). Click here to go to the next FAQ in the "chain" of recent changes.]
• www.compilers.net/Dir/Free/Compilers/CCpp.htm
• www.idiom.com/free-compilers/LANG/C++-1.html
[38.2] Where can I get more information on using MFC and Visual
C++?
• www.visionx.com/mfcpro/
• www.mvps.org/vcfaq
• www.flounder.com/mvp_tips.htm
• msdn.microsoft.com/archive/en-us/dnarvc/html/msdn_mfcfaq50.asp
CString s = "Text";
CStatusBar* p =
(CStatusBar*)AfxGetApp()->m_pMainWnd-
>GetDescendantWindow(AFX_IDW_STATUS_BAR);
p->SetPaneText(1, s);
This works with MFC v.1.00 which hopefully means it will work with other
versions as well.
Here are a few of the many reasons this is not even remotely feasible:
• What makes you think the program was written in C++ to begin with?
• Even if you are sure it was originally written (at least partially) in C++,
which one of the gazillion C++ compilers produced it?
• Even if you know the compiler, which particular version of the compiler
was used?
• Even if you know the compiler's manufacturer and version number, what
compile-time options were used?
• Even if you know the compiler's manufacturer and version number and
compile-time options, what third party libraries were linked-in, and what
was their version?
• Even if you know all that stuff, most executables have had their debugging
information stripped out, so the resulting decompiled code will be totally
unreadable.
• Even if you know everything about the compiler, manufacturer, version
number, compile-time options, third party libraries, and debugging
information, the cost of writing a decompiler that works with even one
particular compiler and has even a modest success rate at generating
code would be significant — on the par with writing the compiler itself from
scratch.
But the biggest question is not how you can decompile someone's code, but why
do you want to do this? If you're trying to reverse-engineer someone else's code,
shame on you; go find honest work. If you're trying to recover from losing your
own source, the best suggestion I have is to make better backups next time.
(Don't bother writing me email saying there are legitimate reasons for
decompiling; I didn't say there weren't.)
[38.5] Where can I get information about the C++ compiler from
{Borland, IBM, Microsoft, Sun, etc.}?
[If anyone has other suggestions that should go into this list, please let me know;
thanks; ([email protected])].
C++ is the language itself, Visual C++ is a compiler that tries to implement the
language.
Recall that when you delete[] an array, the runtime system magically knows
how many destructors to run. This FAQ describes a technique used by some C+
+ compilers to do this (the other common technique is to use an associative
array).
If the compiler uses the "over-allocation" technique, the code for p = new
Fred[n] looks something like the following. Note that WORDSIZE is an imaginary
machine-dependent constant that is at least sizeof(size_t), possibly rounded
up for any alignment constraints. On many machines, this constant will have a
value of 4 or 8. It is not a real C++ identifier that will be defined for your compiler.
// Original code: Fred* p = new Fred[n];
char* tmp = (char*) operator new[] (WORDSIZE + n * sizeof(Fred));
Fred* p = (Fred*) (tmp + WORDSIZE);
*(size_t*)tmp = n;
size_t i;
try {
for (i = 0; i < n; ++i)
new(p + i) Fred(); // Placement new
}
catch (...) {
while (i-- != 0)
(p + i)->~Fred(); // Explicit call to the destructor
operator delete[] ((char*)p - WORDSIZE);
throw;
}
Note that the address passed to operator delete[] is not the same as p.
Compared to the associative array technique, this technique is faster, but more
sensitive to the problem of programmers saying delete p rather than delete[]
p. For example, if you make a programming error by saying delete p where you
should have said delete[] p, the address that is passed to operator
delete(void*) is not the address of any valid heap allocation. This will probably
corrupt the heap. Bang! You're dead!
Recall that when you delete[] an array, the runtime system magically knows
how many destructors to run. This FAQ describes a technique used by some C+
+ compilers to do this (the other common technique is to over-allocate).
If the compiler uses the associative array technique, the code for p = new
Fred[n] looks something like this (where arrayLengthAssociation is the
imaginary name of a hidden, global associative array that maps from void* to
"size_t"):
// Original code: Fred* p = new Fred[n];
Fred* p = (Fred*) operator new[] (n * sizeof(Fred));
size_t i;
try {
for (i = 0; i < n; ++i)
new(p + i) Fred(); // Placement new
}
catch (...) {
while (i-- != 0)
(p + i)->~Fred(); // Explicit call to the destructor
operator delete[] (p);
throw;
}
arrayLengthAssociation.insert(p, n);
Cfront uses this technique (it uses an AVL tree to implement the associative
array).
In other words, some people would like to see name mangling standards
incorporated into the proposed C++ ANSI standards in an attempt to avoiding
having to purchase different versions of class libraries for different compiler
vendors. However name mangling differences are one of the smallest differences
between implementations, even on the same platform.
libg++ (the library used by g++) was probably compiled with debug info ( -g). On
some machines, recompiling libg++ without debugging can save lots of disk
space (approximately 1 MB; the down-side: you'll be unable to trace into libg++
calls). Merely strip-ping the executable doesn't reclaim as much as recompiling
without -g followed by subsequent strip-ping the resultant a.out's.
Use size a.out to see how big the program code and data segments really are,
rather than ls -s a.out which includes the symbol table.
There is also a very old yacc grammar that doesn't support templates,
exceptions, nor namespaces; plus it deviates from the core language in some
subtle ways. You can get that grammar here or here.
These are not versions of the language, but rather versions of Cfront, which was
the original C++ translator implemented by AT&T. It has become generally
accepted to use these version numbers as if they were versions of the language
itself.
A compiler which compiles C++ to C does full syntax and semantic checking on
the program, and just happens to use C code as a way of generating object
code. Such a compiler is not merely some kind of fancy macro processor. (And
please don't email me claiming these are preprocessors — they are not — they
are full compilers.) It is possible to implement all of the features of ISO Standard
C++ by translation to C, and except for exception handling, it typically results in
object code with efficiency comparable to that of the code generated by a
conventional C++ compiler.
Here are some products that perform compilation to C (note: if you know of any
other products that do this, please let me know ( [email protected])):
Note that you typically need to specify the target platform's CPU, OS and C
compiler so that the generated C code will be specifically targeted for this
platform. This means: (a) you probably can't take the C code generated for
platform X and compile it on platform Y; and (b) it'll be difficult to do the
translation yourself — it'll probably be a lot cheaper/safer with one of these tools.
One more time: do not email me saying these are just preprocessors — they are
not — they are compilers.
void myCode()
{
double x = ...;
...
std::string s = "the value is " + stringify(x);
...
}
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
void myCode()
{
std::string s = ...a string representation of a number...;
...
double x = convertToDouble(s);
...
}
You probably want to enhance convertToDouble() so it optionally checks that there
aren't any left-over characters:
inline double convertToDouble(const std::string& s,
bool failIfLeftoverChars = true)
{
std::istringstream i(s);
double x;
char c;
if (!(i >> x) || (failIfLeftoverChars && i.get(c)))
throw BadConversion("convertToDouble(\"" + s + "\")");
return x;
}
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[39.3] Can I templatize the above functions so they work with other types?
Yes — for any types that support iostream-style input/output.
For example, suppose you want to convert an object of class Foo to a std::string, or
perhaps the reverse: from a std::string to a Foo. You could write a whole family of
conversion functions based on the ones shown in the previous FAQs, or you could write a
template function so the compiler does the grunt work.
For example, to convert an arbitrary type T to a std::string, provided T supports syntax
like std::cout << x, you can use this:
// File: convert.h
#include <iostream>
#include <sstream>
#include <string>
#include <typeinfo>
#include <stdexcept>
template<typename T>
inline std::string stringify(const T& x)
{
std::ostringstream o;
if (!(o << x))
throw BadConversion(std::string("stringify(")
+ typeid(x).name() + ")");
return o.str();
}
Here's how to use the stringify() function:
#include "convert.h"
void myCode()
{
Foo x;
...
std::string s = "this is a Foo: " + stringify(x);
...
}
You can also convert from any type that supports iostream input by adding this to file
convert.h:
template<typename T>
inline void convert(const std::string& s, T& x,
bool failIfLeftoverChars = true)
{
std::istringstream i(s);
char c;
if (!(i >> x) || (failIfLeftoverChars && i.get(c)))
throw BadConversion(s);
}
Here's how to use the convert() function:
#include "convert.h"
void myCode()
{
std::string s = ...a string representation of a Foo...;
...
Foo x;
convert(s, x);
...
...code that uses x...
}
To simplify your code, particularly for light-weight easy-to-copy types, you probably
want to add a return-by-value conversion function to file convert.h:
template<typename T>
inline T convertTo(const std::string& s,
bool failIfLeftoverChars = true)
{
T x;
convert(s, x, failIfLeftoverChars);
return x;
}
This simplifies your "usage" code some. You call it by explicitly specifying the template
parameter T:
#include "convert.h"
void myCode()
{
std::string a = ...string representation of an int...;
std::string b = ...string representation of an int...;
...
if (convertTo<int>(a) < convertTo<int>(b))
...;
}
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[39.5] What should be done with macros that have multiple lines?
Answer: Choke, gag, cough. Macros are evil in 4 different ways: evil#1, evil#2, evil#3,
and evil#4. Kill them all!! (Just kidding.)
Seriously, sometimes you need to use them anyway, and when you do, read this to learn
some safe ways to write a macro that has multiple statements.
Here's a naive solution:
#define MYMACRO(a,b) \ (Bad)
statement1; \
statement2; \
... \
statementN;
This can cause problems if someone uses the macro in a context that demands a single
statement. E.g.,
while (whatever)
MYMACRO(foo, bar);
The naive solution is to wrap the statements inside {...}, such as this:
#define MYMACRO(a,b) \ (Bad)
{ \
statement1; \
statement2; \
... \
statementN; \
}
But this will cause compile-time errors with things like the following:
if (whatever)
MYMACRO(foo, bar);
else
baz;
since the compiler will see a } ; else which is illegal:
if (whatever)
{
statement1;
statement2;
...
statementN;
}; // ERROR: can't have }; before else
else
baz;
One solution is to use a do { <statements go here> } while (false) pseudo-loop. This
executes the body of the "loop" exactly once. The macro might look like this:
#define MYMACRO(a, b) \ (Okay)
do { \
statement1; \
statement2; \
... \
statementN; \
} while (false)
Note that there is no ; at the end of the macro definition. The ; gets added by the user of
the macro, such as the following:
if (whatever)
MYMACRO(foo, bar); // The ; is added here
else
baz;
This will expand to the following (note that the ; added by the user goes after (and
completes) the } while (false) part):
if (whatever)
do {
statement1;
statement2;
...
statementN;
} while (false);
else
baz;
This is an acceptable approach, however some C++ compilers refuse to inline-expand any
function that contains a loop, and since this looks like a loop, those compilers won't
inline-expand any function that contains it. Do some timing tests with your compiler to
see; it might be a non-issue to you (besides, you might not be using this within an inline
function anyway).
A possibly better solution is to use if (true) { <statements go here> } else (void)0
#define MYMACRO(a, b) \ (Best)
if (true) { \
statement1; \
statement2; \
... \
statementN; \
} else
(void)0
The preprocessor will expand the usage into the following (note the balanced set of ifs
and elses):
if (whatever)
if (true) {
statement1;
statement2;
...
statementN;
} else
(void)0;
else ^^^^^^^^—that's a do-nothing statement
baz;
The purpose of the strange (void)0 at the end is to make sure you remember to add the ;
just after any usage of the macro. For example, if you forgot the ; like this...
foo();
MYMACRO(a, b) ← bad news: we forgot the ;
bar();
baz();
...then the preprocessor would produce this...
foo();
if (true) {
statement1; \
statement2; \
... \
statementN; \
} else
(void)0 bar(); ← fortunately(!) you'll get a compile-time error-message here
baz();
...which would result in a compile-time error-message. That error-message a lot better
than the alternative: without the (void)0, the compiler would silently generate the wrong
code, since the bar() call would erroneously be on the else branch of the if.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[39.6] What should be done with macros that need to paste two tokens
together?
Groan. I really hate macros. Yes they're useful sometimes, and yes I use them. But I
always wash my hands afterwards. Twice. Macros are evil in 4 different ways: evil#1,
evil#2, evil#3, and evil#4.
Okay, here we go again, desperately trying to make an inherently evil thing a little less
evil.
First, the basic approach is use the ISO/ANSI C and ISO/ANSI C++ "token pasting"
feature: ##. On the surface this would look like the following:
Suppose you have a macro called "MYMACRO", and suppose you're passing a token as
the parameter of that macro, and suppose you want to concatenate that token with the
token "Tmp" to create a variable name. For example, the use of MYMACRO(Foo) would
create a variable named FooTmp and the use of MYMACRO(Bar) would create a variable
named BarTmp. In this case the naive approach would be to say this:
#define MYMACRO(a) \
/*...*/ a ## Tmp /*...*/
However you need a double layer of indirection when you use ##. Basically you need to
create a special macro for "token pasting" such as:
#define NAME2(a,b) NAME2_HIDDEN(a,b)
#define NAME2_HIDDEN(a,b) a ## b
Trust me on this — you really need to do this! (And please nobody write me saying it
sometimes works without the second layer of indirection. Try concatenating a symbol
with __LINE__ and see what happens then.)
Then replace your use of a ## Tmp with NAME2(a,Tmp):
#define MYMACRO(a) \
/*...*/ NAME2(a,Tmp) /*...*/
And if you have a three-way concatenation to do (e.g., to paste three tokens together),
you'd create a name3() macro like this:
#define name3(a,b,c) name3_hidden(a,b,c)
#define name3_hidden(a,b,c) a ## b ## c
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[39.7] Why can't the compiler find my header file in #include "c:\test.h" ?
Because "\t" is a tab character.
You should use forward slashes ("/") rather than backslashes ("\") in your #include
filenames, even on operating systems that use backslashes such as DOS, Windows, OS/2,
etc. For example:
#if 1
#include "/version/next/alpha/beta/test.h" // RIGHT!
#else
#include "\version\next\alpha\beta\test.h" // WRONG!
#endif
Note that you should use forward slashes ("/") on all your filenames, not just on your
#include files.
Note that your particular compiler might not treat a backslash within a header-name the
same as it treats a backslash within a string literal. For instance, your particular compiler
might treat #include "foo\bar\baz" as if the '\' chars were quoted. This is because
header names and string literals are different: your compiler will always parse
backslashes in string literals in the usual way, with '\t' becoming a tab character, etc.,
but it might not parse header names using those same rules. In any case, you still
shouldn't use backslashes in your header names since there's something to lose but
nothing to gain.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[39.8] What are the C++ scoping rules for for loops?
Loop variables declared in the for statement proper are local to the loop body.
The following code used to be legal, but not any more, since i's scope is now inside the
for loop only:
for (int i = 0; i < 10; ++i) {
...
if ( /* something weird */ )
break;
...
}
if (i != 10) {
// We exited the loop early; handle this situation separately
...
}
If you're working with some old code that uses a for loop variable after the for loop, the
compiler will (hopefully!) give you a warning or an error message such as "Variable i is
not in scope".
Unfortunately there are cases when old code will compile cleanly, but will do something
different — the wrong thing. For example, if the old code has a global variable i, the
above code if (i != 10) silently change in meaning from the for loop variable i under
the old rule to the global variable i under the current rule. This is not good. If you're
concerned, you should check with your compiler to see if it has some option that forces it
to use the old rules with your old code.
Note: You should avoid having the same variable name in nested scopes, such as a global
i and a local i. In fact, you should avoid globals altogether whenever you can. If you
abided by these coding standards in your old code, you won't be hurt by a lot of things,
including the scoping rules for for loop variables.
Note: If your new code might get compiled with an old compiler, you might want to put
{...} around the for loop to force even old compilers to scope the loop variable to the
loop. And please try to avoid the temptation to use macros for this. Remember: macros
are evil in 4 different ways: evil#1, evil#2, evil#3, and evil#4.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[39.9] Why can't I overload a function by its return type?
If you declare both char f() and float f(), the compiler gives you an error message,
since calling simply f() would be ambiguous.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[39.11] How can I create two classes that both know about each other?
Use a forward declaration.
Sometimes you must create two classes that use each other. This is called a circular
dependency. For example:
class Fred {
public:
Barney* foo(); // Error: Unknown symbol 'Barney'
};
class Barney {
public:
Fred* bar();
};
The Fred class has a member function that returns a Barney*, and the Barney class has a
member function that returns a Fred. You may inform the compiler about the existence
of a class or structure by using a "forward declaration":
class Barney;
This line must appear before the declaration of class Fred. It simply informs the compiler
that the name Barney is a class, and further it is a promise to the compiler that you will
eventually supply a complete definition of that class.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
[39.12] What special considerations are needed when forward declarations
are used with member objects?
The order of class declarations is critical.
The compiler will give you a compile-time error if the first class contains an object (as
opposed to a pointer to an object) of the second class. For example,
class Fred; // Okay: forward declaration
class Barney {
Fred x; // Error: The declaration of Fred is incomplete
};
class Fred {
Barney* y;
};
One way to solve this problem is to reverse order of the classes so the "used" class is
defined before the class that uses it:
class Barney; // Okay: forward declaration
class Fred {
Barney* y; // Okay: the first can point to an object of the second
};
class Barney {
Fred x; // Okay: the second can have an object of the first
};
Note that it is never legal for each class to fully contain an object of the other class since
that would imply infinitely large objects. In other words, if an instance of Fred contains a
Barney (as opposed to a Barney*), and a Barney contains a Fred (as opposed to a
Fred*), the compiler will give you an error.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
class Barney {
public:
void method()
{
x->yabbaDabbaDo(); // Error: Fred used before it was defined
}
private:
Fred* x; // Okay: the first can point to an object of the second
};
class Fred {
public:
void yabbaDabbaDo();
private:
Barney* y;
};
There are a number of ways to work around this problem. One workaround would be to
define Barney::method() with the keyword inline below the definition of class Fred
(though still within the header file). Another would be to define Barney::method()
without the keyword inline in file Barney.cpp. A third would be to use nested classes.
A fourth would be to reverse the order of the classes so the "used" class is defined before
the class that uses it:
class Barney; // Okay: forward declaration
class Fred {
public:
void yabbaDabbaDo();
private:
Barney* y; // Okay: the first can point to an object of the second
};
class Barney {
public:
void method()
{
x->yabbaDabbaDo(); // Okay: Fred is fully defined at this point
}
private:
Fred* x;
};
Just remember this: Whenever you use forward declaration, you can use only that
symbol; you may not do anything that requires knowledge of the forward-declared class.
Specifically you may not access any members of the second class.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
class Barney {
std::vector<Fred> x; // Error: the declaration of Fred is incomplete
};
class Fred {
Barney* y;
};
One solution to this problem is to change Barney so it uses a std::vector<> of Fred
pointers rather than a std::vector<> of Fred objects:
class Fred; // Okay: forward declaration
class Barney {
std::vector<Fred*> x; // Okay: Barney can use Fred pointers
};
class Fred {
Barney* y;
};
Another solution to this problem is to reverse the order of the classes so Fred is defined
before Barney:
class Barney; // Okay: forward declaration
class Fred {
Barney* y; // Okay: the first can point to an object of the second
};
class Barney {
std::vector<Fred> x; // Okay: Fred is fully defined at this point
};
Just remember this: Whenever you use a class as a template parameter, the declaration of
that class must be complete and not simply forward declared.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]