As part of my day job, I have a weekly email discussion with other engineers about a random, small topic in C or C++. These discussions are usually not large enough to warrant a full blog post, but can be valuable nonetheless. This page is a dumping ground for the tidbits we’ve discussed, and so it should be updated weekly (give or take).
Table of Contents
Small integer types and type promotion
Is char signed or unsigned?
Bit Field Madness!
Expressions with Side-Effects
Array Parameters
Passing Parameters by Value
Returning by Value
Writing Library APIs
Quick STL Construction Tips
Object Slicing
Macros Aren’t Easy
Useful Online Tools
Enums, Structs, and Unions. Oh my!
Under-specified Behavior
The Conditional Operator
Const Correctness
How #include Works
C++11’s static_assert
realloc is Tricky
Library Boundaries
Always Best to be Explicit
Const-Correct Typedefs
Pointer Alignment
Braced Initializers
Class Template Linkage
Empty Classes
Character Sets
Templated Base Classes
Character Widths
Type Variance
Template Typedefs
Range-based For Loops
Name Visibility, Access Control and Overload Resolution
Assignment Operators
Polymorphism in Constructors and Destructors
Delegating Constructors
Better Living Through unique_ptr
Override and Final
Deleted and Defaulted Functions
Null Pointer Checking with new/delete
SFINAE
Abstract Base Classes
Translation Units
Iterators
RAII Objects
Integer Division
Parameter Evaluation Order
Hex Floating-Point Literals
When to Specify virtual
Const-Correct Methods
Lambda Functions (Part 1)
Lambda Functions (Part 2)
Lambda Functions (Part 3)
Lambda Functions (Part 4)
Lambda Functions (Part 5)
Unaligned Memory Access
Floating-Point Equality
Small integer types and type promotion
When an expression involves a small integer type (char, short, bit fields and enums), the small integer type is always promoted. The rule for integer promotion is that all small integer types will be promoted to int if int is able to represent all possible values for the type, otherwise the value is promoted to unsigned int.
This promotion happens only for small integer types that are part of a unary, binary or ternary operator *other than ||, && and !*, or is the control expression of a switch statement.
Generally speaking, this is a detail you don’t have to think about because everything just works. But it is something you need to be aware of because it can have unintended consequences. For instance:
unsigned char c = 0x60;
What is the value of “~c”?
You might think it’s an unsigned char with the value 0x9F (159), but it’s really a signed int with the value -97. But it gets even worse. Imagine performing a right shift operation after the one’s complement. In that case, you now get undefined behavior because you may or may not be shifting in more ones (right shift of a signed integer yields undefined behavior for negatives numbers).
A good rule of thumb when dealing with small integer types is to always assign back into the same small integer type (or cast) before performing the next operation. This ensures that you get the proper bit pattern. For instance: ((unsigned char)~c) >> 1 instead of (~c) >> 1.
#1 : C, C++
Would you guess that char is signed or unsigned?
Sorry, that was a trick question! char can be either/or because it is implementation defined. So if you are using char as a small integer (to hold numeric values), you may have a bug lurking. For numeric purposes, always be explicit and specify either signed char or unsigned char instead of assuming. Use the char datatype for holding only character data.
This can have an important impact with integer promotion as well, since a numerical value stored within a char may wind up being sign extended into a signed int instead of left as a small unsigned value.
#2 : C, C++
Bit fields are the least-specified language feature in C and C++ (easily). There is so much undefined and implementation defined behavior that it’s best to simply avoid them altogether. But sometimes you can’t avoid using them, especially if you work with hardware. So what *is* safe to do with a bit field?
It turns out the answer is: not nearly as much as you’d think. You can create a bit field that is usable only by a single version of a single compiler, only with an explicitly signed or unsigned int, and cannot use more than 32 bits in the bitfield. That’s it.
This means that you cannot:
- use any other datatype aside from signed int or unsigned int
- use a bit field variable meant to be used by a different language (like C# interop)
- use a bit field variable meant to span across different compilers (such as a bit field in a structure in a framework)
- use a bit field variable meant to span across different versions of the same compiler
- rely on the layout of the bits in memory
- take the address of a member of a bit field
Long story short, be extra careful if you use a bit field and understand that your code probably doesn’t work by design unless you are incredibly careful.
Fun tidbit: Microsoft screwed up and used bit fields as part of the Win32 API, and it’s caused considerable amount of pain for the MSVC team. The DCB structure used for serial communications uses bit fields, and so the layout of bit fields in MSVC’s compiler hasn’t changed in decades, regardless of bugs in their implementation. Why? Because Visual Basic needed to be able to work with the structure for declares! So changing anything about bit fields would then break all those applications (while standards-compliant C and C++ applications would continue to work). Oops.
#3 : C, C++
Be careful when using related expressions with side effects in C++, as many times the order of evaluation is undefined by the standard. Consider these example:
// Examples of what not to do foo( i++, i ); x = someArray[ i ] + i++;
It may be surprising to you, but both of those are dangerous operations. The order in which parameters to a function call are evaluated is undefined except that all parameters will be evaluated before the function call is made. So you know i++ will happen at some point, but you won’t know whether it happens before i’s value is determined (for the second parameter) or not. Even with the array subscript you have a problem — you don’t know whether i has been incremented before or after it is used as an array subscript! What’s more, because this is not a precedence issue, adding parenthesis will not change the behavior.
This can lead to some very hard to trace bugs, especially in cross-platform code! And sometimes the relationships are even harder to see. For instance:
int i; int bar() { return ++i; } int baz() { return i * 10; } void quux( int i, int j ) { ::printf( "i: %d, j: %d\n", i, j ); } int main( void ) { i = 100; quux( bar(), baz() ); return i; }
In this code, you have no idea what will be printed by quux, and you also don’t know what value will be returned by main. It could be 1010 or it could be 1001!
The term used in the standard to describe this is called “sequence points”, and it’s a particularly difficult topic to wrap your mind around. But the basic rule of thumb to follow is to avoid situations where order of evaluation matters in the first place! If there are side-effects you need to observe in a particular order, be explicit. For instance, if we want to make sure main always returns 1001 in our example, do:
int main( void ) { i = 100; int j = baz(); quux( bar(), j ); return i; }
#4 : C/C++
What is wrong with the following declaration?
void foo( int i[ 10 ] );
Technically, nothing. However, it likely doesn’t behave the way you think it behaves. Array indices in function parameters are nothing more than decorative pointers. The 10 in there means nothing, and isn’t enforced by the compiler. For instance, this is legal:
int i[ 2 ]; foo( i ); // Won't throw an error
This phenomenon is called “pointer decay.” The only way to avoid it is by garbling the function declaration into this unreadable mess:
void foo( int (&i)[ 10 ] );
The morale of the story is: if exact array bounds are important to a function, declare a reference to the array as the parameter. If exact bounds are merely suggestive, pass a naked pointer and a count/size parameter instead. Another option which avoids the problem is to use a “safer” datatype such as std::vector.
#5 : C/C++
Passing Parameters by Value
Be wary of any code which passes a class or struct object around by value via a parameter. This has hidden expense associated with it because it means the object must be *copied* on input to the class. Instead, it’s best to pass the object by reference. If you don’t want the object to be modifiable, then you can pass it as a const reference. For instance:
// Don't do this void Foo( std::string bar ); // Do this instead void Foo( const std::string& bar );
By passing a reference, you don’t have to pay for any copies being made (nor the side effects associated with such a copy).
#6: C++
Remember how you’re supposed to be wary of any code which passes a class or struct object by value as a parameter? Even more important is to be skeptical of code which returns a class or struct by value! This can have unintended consequences beyond just being inefficient. Consider the following code:
std::string foo( void ) { std::string ret( "This is a test" ); return ret; }
It may look harmless, and may even work on occasion for you. But it can also hide bugs. For example:
const char *str = foo().c_str(); ::printf( "%s\n", str );
That code will cause a crash because foo is returning a temporary copy of a std::string, you calling c_str on it, which returns a pointer to the underlying string’s internal buffer. Then the temporary copy is destroyed once the statement finishes, and you are left with a dangling pointer stored in str, which you then use in printf. Oftentimes this will result in a crash, but there’s always a good possibility that you won’t crash every time. It depends entirely on the way memory is laid out and used for your application.
If you must use classes by value, pass one in as a “return parameter” to the function. This forces the memory management to be consistent and reduces the chance for errors. Like this:
void foo( std::string& out ) { std::string ret( "This is a test" ); out = ret; } std::string val; foo( val ); const char *str = val.c_str(); ::printf( "%s\n", str );
#7 : C++
When working on library code, be careful of what can cross your API boundaries. Some things are safe to use, and others are unsafe to varying degrees. Some things will be confusing or inconsistent to work with, but can be used. Other things are simply non-deterministic enough that using them would be almost impossible. But there are also things which cause outright crashes!
Confusing/Inconsistent
- Using variably-sized types such as enums, wchar_t or long
- Bitfields (the ordering, padding and alignment of the fields are up to the compiler)
Hard/Impossible to Use
- Non-POD types such as classes, or structures with virtual methods, etc (the layout of the objects and name mangling is compiler-specific)
- Functions that have not been exported with “C” linkage (the name mangling scheme is compiler-specific and often changes)
Crash
- Not being explicit about the calling convention used on x86
- Throwing exceptions across library boundaries (exceptions do not have a stable ABI and so cannot be caught in this situation)
- Mismatched memory allocation/deallocation (the library and application may be using different allocators/deallocators)
All of these (and there are more!) are examples of places where you can cross API boundaries between the application and the library and cause a lot of headaches for users. So when you write an API that is exposed from the framework, think carefully about whether the syntax and semantics are actually safe to use.
#8 : C/C++
You can initialize a vector from an array by using the vector’s constructor. Vector has a constructor which accepts two input iterators — the start and the end of the data. This works with arrays because Iterators can be created from pointers (pointers automatically convert into random access iterators). So the initialization will look something like this:
int myArray[] = { 0, 1, 2, 3, 4, 5 }; std::vector< int > v( myArray, myArray + 6 ); // You could use _countof too
Using iterators like this is a very handy way to perform many tasks. For instance, if you are converting a string from one encoding to another, you can do this:
// Determine the number of characters required size_t numCharacters = CalculateLengthForConversion( myUTF16String ); // Allocate a vector that can hold that many characters std::vector< char > v( numCharacters ); // Pass in the UTF-16 string and a pointer to the char buffer to fill out ConvertUTF16ToUTF8( myUTF16String, &v[ 0 ] ); // Convert the vector into a string std::string str( v.begin(), v.end() );
The nice thing about these “tricks” is that they remove all of the boilerplate code, allowing you to focus on the purpose of the algorithm more than the mechanics.
#9 : C++
Object Slicing
Can you spot the bug in this code?
class Base { public: virtual void DoSomething() {} }; class Derived : public Base {}; void bar_then_free( Base *items, unsigned count ) { for (unsigned i = 0; i < count; ++i) { items[ i ].DoSomething(); } delete [] items; } void foo() { Derived *items = new Derived[ 12 ]; bar_then_free( items, 12 ); }
The problem is with the call to delete[]! Attempting to use a vector delete where the dynamic type of the object is different from the static type of the object is undefined. In this case, the static type seen by delete[] is Base, but the dynamic type is actually Derived, so this code may not work the way you need it to. My example is more complex than it need be, the following has the same bug:
Base *items = new Derived[ 12 ]; delete [] items;
So where’s the undefined behavior? It’s with the way delete[] is implemented. When you use a vector delete, the items in the array are freed (from the last index to the first index) and then the memory for the entire array is freed. So it looks something like this:
template <typename T> void vector_free( void *memory, unsigned count ) { unsigned char *ptr = ((unsigned char *)memory) + (sizeof( T ) * (count - 1)); while (ptr >= memory) { reinterpret_cast< T * >( ptr )->~T(); ptr -= sizeof( T ); } free( memory ); }
The undefined behavior comes from walking the array. I could have written this using regular array notation, but it would have obscured the problem. The issue is with the sizeof the elements. In our example, T would be Base, not Derived and sizeof( Base ) does not have to be the same as sizeof( Derived )! So the memory being passed to operator delete to free the individual elements may very well be wrong, which is why this is undefined behavior.
The really astute may have picked up on something here. It’s not that delete[] is causing the undefined behavior — it’s the notion of Base[] being the same fundamental type as Derived[]! You cannot even do this:
Base *items = new Derived[ 12 ]; for (unsigned i = 0; i < 12; ++i) { items[ i ].DoSomething(); }
This problem is commonly known as “object slicing” (because part of the object is silently sliced off), and you have to be very careful of it — I have seen our own code bases suffering from this. The confusion of pointers and arrays are a C legacy, but do not always match up as nicely as we sometimes like to assume as C++ programmers!
#10 : C++
Macros are hard to get right! Consider the following examples:
#define ABS( a ) ((a >= 0) ? a : -a) #define MIN( a, b ) ((a < b) ? (a) : (b))
Can you spot all the ways these can be misused? What happens if you pass in an expression to them? What about an expression with side effects? Consider the following:
int z = ABS( x - y ); // Oops! int k = MIN( ++i, j ); // Oops!
In the case of calling ABS, look at what that expression would expand into. ((x – y >= 0) ? x – y : -x – y). That’s not correct! And in the case of MIN, look at what that expands into. ((++i < j) ? (++i) : (j)) — so if i + 1 is less than j, it actually returns i + 2 because it increments i twice! When writing macros, always be sure to make judicious use of parenthesis. The ABS macro could have been corrected by putting parenthesis around all of the terms of the ?: operator. And when calling macros, avoid using expression, function calls or anything with side effects if humanly possible. It can be very easy to get unexpected behavior with even the most harmless-looking macros. Instead of using macros, consider alternatives such as template functions in C++. If you do end up using a macro, try to make it easily identifiable as a macro by making the identifier all caps. This way, the caller can know what to avoid when using the macro. #11 : C/C++ Useful Online Tools
Have you ever wanted to do some quick one-off programs just to see the output, but don’t want all the hassle of creating a new project/file, compiling it yourself, etc? Well, you’re in luck: http://ideone.com allows you to enter in source code that will be executed on the server and the results will be returned to you. It supports a wide variety of languages, but most interestingly for us, it supports C, C99, C++03, C++11, C# and Objective-C. It’s a pretty neat little webpage that I find myself going to more and more often to answer those “I wonder how that works” sort of questions. It’s certainly cut down on my disk space clutter! I’ve also found that it’s handy in identifying compiler-specific behavior compared to MSVC (since it uses gcc for its C variants).
If you find yourself wondering what the compiler might spit out in terms of assembly for a particular problem, you can go to http://gcc.godbolt.org/ to see. They currently support gcc and clang, but I wouldn’t be surprised to see the list continue to grow. You can even pick the compiler options so you can see what happens at different optimization levels!
#12 : C/C++/Others
Enums, Structs and Unions. Oh my!
When it comes to enums, structs and unions, C is a bit different from C++ in the way it works. Let’s look at a declaration from both perspectives:
struct foo { int i; };
In C++, when you declare a structure, you can use it by name with no adornments. But this is not true in C! In C, the name of the type includes the type specifier. So:
foo f; // Legal only in C++ struct foo f; /* Legal in C and C++ */
One way to think of the C types is that there are really four namespaces: global, struct, enum and union. You use the keyword struct to access the struct namespace, enum for the enum namespace and union for the union namespace.
If you are writing C code, you can still declare a variable “the C++ way”, but it requires an extra step. When you typedef a type in C, it automatically imports it into the global namespace. So in this fashion, you can create a type allowing you to skip the adornments.
typedef struct foo foo; foo f; /* Legal in C and C++ now */
Additionally, you could make an anonymous structure in the struct namespace, but give it a valid name in the global namespace:
typedef struct { int i; } bar; bar f; /* Legal in C and C++ now */
This is important to keep in mind if you are writing an SDK with a C header file, because compilers generally won’t help you out with this. If you have a C header file, you should either typedef the type into the global namespace, or use the adornments in your parameters and return types.
#13 : C/C++
You’ve probably heard that C and C++ tend to have a fair amount of undefined behavior. But just how bad is it really? Well, in C++03 (the specification prior to the current standard, C++11) has 85 undefined behaviors. However, it also has unspecified, implementation defined, indeterminate and behaviors which require no diagnostic (warning or error) as well. All told it has just shy of 200 behaviors that are unreliable! Some gems:
- Not terminating a string or character literal results in undefined behavior. Not an error! Just “whatever goes.”
- Calling a class’ virtual function from its constructor or destructor is undefined.
- What happens when dereferencing a null pointer is undefined.
- The alignment of bitfields is implementation defined.
- Prior to C++11, you have no control over the integer type used by an enum declaration; it’s implementation defined.
There are so many random things that don’t have concrete rules associated with them — why?? It is because of all these unreliable behaviors that C and C++ are so highly-optimized. By leaving details up to the compiler, the compiler is able to optimize your code. For instance, since dereferencing a null pointer is undefined, the compiler will optimize the following code:
void foo( int *i ) { int j = *i; // Note the dereference if (i) { ::printf( "%d\n", j ); // Using the result of the dereference } }
The if statement and all that it contains can be stripped out by the compiler, because the assignment to j has already told the compiler “this thing won’t be null, since it if was null, any particular behavior is fine.” Obviously, this is a relatively contrived example (and it shows you how optimized code can sometime behave far differently than logic might dictate!), but it demonstrates the theory. The compiler is able to make assumptions on your behalf which result in smaller and/or faster code. Without all this unreliability inherent in the language, it would be considerably more difficult to optimize people’s code. Not impossible, just more difficult.
If you’d like a more detailed description about why under-specified behavior happens, it turns out Eric Lippert (on the C# compiler team) wrote about it this week as well: http://blogs.msdn.com/b/ericlippert/archive/2012/06/18/implementation-defined-behaviour.aspx
#14 : C/C++
What is the output of the following valid C++ code?
void some_func( int i ) { ::printf( "Integer: %d\n", i ); } void some_func( double d ) { ::printf( "Double: %g\n", d ); } void foo( void ) { int i = 42; double d = 4.2; some_func( true ? i : d ); some_func( false ? i : d ); }
The conditional operator (?:) has an interesting and easy to overlook behavior in that it requires the true and false types to be the same. So if you guessed Integer: 42 and Double: 4.2, you’re actually wrong. It will print out Double 42 and Double 4.2 because the compiler had to perform a conversion for the integer. The rules behind what conversion happen are quite complex (you can see them in the standard in 5.16), so my suggestion is to always ensure your types match to avoid any confusion or undefined behavior. At the very least, it helps to be aware that this behavior can happen so you don’t spend too long wondering why the wrong overload gets called.
#15 : C/C++
Const-correctness is a topic near and dear to my heart. But even I get tripped up by this on occasion! There is a big difference between these declarations:
class C { public: void CTest1() {} void CTest2() const {} }; void foo1( const C *s ); void foo2( C * const s ); void foo3( const C * const s );
foo1’s parameter is declared as a pointer to a constant C, foo2’s parameter is declared as a constant pointer to C, and foo3’s parameter is declared as a constant pointer to a constant C. The differences can be subtle but drastic. foo1 cannot call CTest1, foo2 cannot assign into s but can call CTest1, and foo3 cannot call CTest1 or assign into s. Eg)
void foo1( const C *s ) { s->CTest1(); // Illegal s->CTest2(); // Legal s = new C(); // Legal } void foo2( C * const s ) { s->CTest1(); // Legal s->CTest2(); // Legal s = new C(); // Illegal } void foo3( const C * const s ) { s->CTest1(); // Illegal s->CTest2(); // Legal s = new C(); // Illegal }
You may wonder why you would ever want to declare a constant pointer (like foo2 and foo3). Consider the case where you have an array of C’s that you don’t want the caller to modify. Eg)
void foo4( ???? s, size_t count ) { for (size_t i = 0; i < count; ++i) { // We want to prevent this from happening! s[ i ]->CTest1(); // This too! s[ i ] = new C(); } }
In this case, you would want the parameter to be a pointer to a constant pointer to a constant C. That’s a mouthful! But it looks like this: const C* const *s. The trick for remembering what a declaration means: const is part of the declaration type (it’s called a “qualifier”), and you read declaration types from right-to-left. So const C* const *s is read as: s is a pointer (*s) to a constant pointer (* const) to a constant C pointer (const C*).
#16 : C/C++
The way the #include directive works is quite a story. It turns out that almost everything about #include is implementation defined by the compiler when it comes to how to find the files. This means everything from the behavior of “” versus <> to the way paths are represented is a crapshoot. But there are some de facto behaviors that have emerged over the years that you can sort of rely on. Specifically:
* Use <> for system-defined header files (including libraries installed on the machine)
* Use “” for user-defined header files that you create yourself
* This is because of the way the compilers typically implement header search algorithms. <> looks in the system paths, and “” looks in the local directory structure
* You can use \ or / as a path separator on Windows because the file system supports it. But you can only use / on OS X and Linux for the same reason.
* Assume that strings are case sensitive, even if the file system isn’t, because some compilers care (as do some file systems)
This information is of particular importance to people working on shared codebases like Prism or XRD because their header files are used from many different compilers: MSVC, gcc, clang are used internally, but since these go out to OEMs you also have to worry about mingw, Code Warrior (well, maybe not Code Warrior), Bloodshed and Comeau. So while the above rules aren’t actually mandated by any standard, there is at least a passing chance that a C/C++ compiler will be able to interpret your #include directives the way you had intended.
#17 : C/C++
One of the new language features in C++11 is the static_assert. It’s like an assert statement, except it runs at compile time instead of at run time. If the assert fails, then a compiler error message is generated.
This is a great feature when developing code to be used by multiple people, or across compilers, etc. You can statically assert the build environment is sane so that the next guy doesn’t have head-scratching problems. For instance, let’s say you expect the size of a structure to remain a multiple of 16 bytes for efficiency reasons. You could accomplish this by using a static_assert like this:
static_assert( (sizeof( struct SomeSpeedyStruct ) % 16) == 0, "SomeSpeedyStruct needs to be a multiple of 16 bytes" );
If SomeSpeedyStruct were to change so that it’s no longer a multiple of 16 bytes in size, then the compiler will emit an error and print the message “SomeSpeedyStruct needs to be a multiple of 16 bytes”.
This is handy for more than just determining the size of structures at compile time, of course. You can use any constant expression that evaluates to a bool as the first parameter to static_assert. You can check whether a macro has a specific value for compiler or library features, the size of specific datatypes (for instance, that a long is 32- or 64-bits), etc.
It’s not something you’re like to use every day, but it’s a good thing to remember when writing code that makes assumptions which can be checked by the compiler. They have no cost at runtime, so there’s no performance concerns.
#18 : C++
Be careful when using the realloc C API, because it is a poorly designed function that can bite you in strange ways. Specifically, can you name what’s wrong (if anything) with the following code snippets:
// 1 void *someMemory = ::malloc( 12 ); ::realloc( someMemory, 32 ); // 2 void *someMemory = ::malloc( 12 ); someMemory = ::realloc( someMemory, 32 ); // 3 void *someMemory = ::realloc( 0, 32 ); // 4 int *someMemory = (int *)::malloc( sizeof( int ) ); int *someOtherMemory = (int *)::realloc( someMemory, sizeof( int ) ); if (someMemory == someOtherMemory) { *someMemory = 1; *someOtherMemory = 2; ::printf( "%d %d\n", *someMemory, *someOtherMemory ); }
The only one of those snippets that works without problems is #3! The problem with #1 is that it assumes the re-allocation can happen in place, without needing to allocate a different chunk of memory and copying the old data over. The problem with #2 is that it does handle in-place allocations as well as new allocations, but it doesn’t handle the failure case where you are unable to allocate the new memory (in which case you will leak the someMemory pointer). #4 is a problem because someMemory has actually been *deallocated*, and accessing memory after it’s been deallocated is undefined behavior. In some compilers, you will actually see 1 2 printed out on the command line!
The proper way to use realloc is to assume it is implemented like this:
void *realloc( void *memory, size_t size ) { void *ret = ::malloc( size ); if (ret) { ::memcpy( ret, memory, size ); ::free( memory ); return ret; } return 0; }
So you should always assume the pointer coming back from realloc is different from the one you passed in, and the one you passed in has been deleted. Except if realloc returns null, in which case the original memory is still yours to work with. All the usual rules apply with regards to deleted or allocated memory. Like this:
void *newMemory = ::realloc( otherMallocedMemory, newSize ); if (!newMemory) { ::free( otherMallocedMemory ); handleFailure(); } otherMallocedMemory = newMemory;
#19 : C/C++
The way exceptions are defined is up to the implementing compiler, and can even change from version to version of the compiler! This isn’t a problem when all exceptions are thrown and caught from within the same executable object. However, if you are writing a library (either static or dynamic), this is hugely problematic. The rule of thumb to follow is to *never* allow exceptions of any kind to cross library boundaries. This goes for “built in” exceptions like the ones exposed by the STL, too.
Speaking of crossing library boundaries, another incredibly important thing to understand is that memory allocation and deallocation needs to be paired within the same library. You cannot allocate memory in one library and deallocate it in another for much the same reason you can’t throw exceptions across library boundaries: the implementations can (and will be) totally different. So if your library allocates a chunk of memory, do not have the caller attempt to free/delete it! You need to provide an API to do that.
Another library boundary issue has to do with C++ class definitions. There is no standard ABI for C++ classes (though some systems like OS X will define a standard ABI, most systems don’t), and so there’s no safe way for your C++ class implementations to cross library boundaries. Compiler A may lay the class out one way in the library, and Compiler B may think the class is laid out an entirely different way and crash when trying to use it. If you are making a library that you want to expose C++ classes from, you *must* put the class definition in the header file itself (instead of only putting the declaration there). This way, when the client compiler sees the class, it has to generate all of its own code for the class instead of relying on code generated by the compiler that built the library. Consequently, this is why you can see the source code to almost the entire STL library. I say almost because the STL does have some feature requirements that usually tie it to a specific compiler (by making the STL use special intrinsics).
#20 : C/C++
Always Best to be Explicit
In C++, when a class has a constructor with a single parameter, it is considered a copy constructor automatically by the compiler. This is quite handy in some cases, and quite surprising in others. For instance:
class C { const char *mData; public: C( const C& rhs ) { mData = ::strdup( rhs.mData ); } C( const char *data ) { mData = ::strdup( data ); } };
In this case, the compiler will automatically call the copy constructor for you:
C c( "This is a test" ); // Regular constructor call C c2 = c; // Copy constructor call C c3 = "This is another test"; // Copy constructor call
One of the dangers of copy constructors is that they can be unintentionally called:
if (c = c3) {} // Oops, copy constructor called!
Thankfully, C++ has a way for you to deal with this a la the “explicit” keyword. This allows you to tell the compiler “this is a constructor, and can only be called explicitly.” You simply put the explicit keyword in front of the constructor you care about. Like this:
class C { ... explicit C( const char *data ) { ... } ... }; C c( "This is a test" ); // Regular constructor call C c2 = c; // Copy constructor call without explicit keyword C c3 = "This is another test"; // Error because the const char * constructor is explicit C c4( c ); // Copy constructor call
When writing your classes, you should get in the habit of making all of your single parameter constructors explicit. This reduces the chances of your class being accidentally misused, and it encourages more readable usage of the class (with good error reporting when you forget).
#21 : C++
Const-Correct Typedefs
In the past, I’ve spoken about how const-correctness is near and dear to my heart (#16). But writing const correct code can be challenging, and when you throw typedefs into the mix, it can be downright hard. See if you can spot the problem with the following:
struct Foo { int i; }; typedef struct Foo * FooPtr; void bar( const FooPtr fp ) { fp->i = 12; } void baz( const struct Foo *fp ) { fp->i = 12; }
The function baz will fail to compile because fp is const, but bar will compile properly because fp isn’t const. What’s going on here?
C and C++ are a little bit obtuse about the way pointer declarations work (references too, in C++). The pointer follows the declarator, not the type. So when you have struct Foo *fp, the type is struct Foo, and the declarator is *fp. That’s why you are able to make declarations like: int i = 12, *pi; That declares two variables of type int. i is one of them, and *pi is the other. So how does this knowledge help us? In the case of baz, you are declaring a pointer named fp (*fp) which has the type const struct Foo. This is described in the standard under [dcl.decl]p2 and is the basis behind the general rule that you read declarations from right-to-left. It’s a pointer to a const struct Foo, or: struct Foo const *fp (they’re equivalent declarations).
In the case of bar, you are declaring a name (fp) to a const FooPtr, and FooPtr is a struct Foo. You might think this means you get a declaration const struct Foo *fp, but that’s not the case. What you get is a constant pointer to struct Foo, or struct Foo * const fp; So in this case, it’s the *pointer* that’s constant, and not the variable! You can see this for yourself by altering bar slightly:
void bar( const FooPtr fp ) { fp->i = 12; // OK ++fp; // Error; trying to alter the pointer! }
This is why you must make a separate typedef for a pointer to a const struct Foo, like this:
typedef struct Foo *FooPtr; typedef struct Foo const *ConstFooPtr;
Or simply forgo the use of the typedef in your declarations (which may wind up with uglier code).
22 : C/C++
Pointer Alignment
Pointer casting between types can be a dangerous operation, even when it looks benign. For instance:
uint8_t *p1; unit32_t *p2 = (uint32_t *)p1;
The operation may look reasonable, but in fact can cause crashes when reading or writing with p2. This is because pointers have an alignment associated with them based on their pointed-to type. The one byte pointer may have a one-byte alignment on some platforms, while the four byte pointer may have a four-byte alignment. So attempting to derefrence the pointer on a one byte boundary could crash.
23 : C/C++
Braced Initializers
Did you know that you can use braced initializer lists to initialize structures and arrays? This is one of those handy short-hand concepts that have been supported in C and C++ for quite a while, and has only gotten better with time. The rule is that the braces perform in-order initialization of members. So, for instance:
struct foo { int i; double d; }; struct foo f = { 1, 1.0 }; // f.i will be 1, f.d will be 1.0 int i[ 3 ] = { 1, 2, 3 }; // i[ 0 ] will be 1, i[ 1 ] will be 2, i[ 2 ] will be 3
This even works for arrays of structures, arrays within structures and embedded structures!
struct bar { struct foo f; int j; char c[ 3 ]; }; // Kind of ugly and to be avoided !! struct bar b = { 1, 1.0, 2, "foo" }; // b.f.i will be 1, b.f.d will be 1.0, b.j will be 2, b.c will be "foo" // More clear and to be preferred!! struct bar b2 = { { 1, 1.0 }, 2, "foo" }; // same values as above, but less prone to break if the structure changes struct bar f[ 2 ] = { { 1, 1.0, 1, "foo" }, { 2, 2.0, 2, "bar" } };
You can also define the size of an array by using a braced initializer list:
int i[] = { 1, 2, 3 }; // Will make i[3] with the values filled out
In C++11, braced initializer lists become a more standardized feature, allowing you to use them anywhere to perform any kind of initialization. For instance:
class C { public: explicit C( const char *str ) {} C( const char *str, int i ) {} }; // Old style C c( "foo" ); // New style C c2{ "foo" }; // note the use of {} instead of () C c3 = { "foo", 2 };
You can get away with specifying less values in the braced initializer list than members to be initialized, but that is considered a terrible practice and to be a source of hard-to-find bugs. However, there is one exception to that rule — zero initializing.
struct foo f = { 0 }; // Perfectly fine, initializes all members of f to 0/nullptr/0.0
24 : C++
Class Template Linkage
Template definitions have what is called “internal linkage.” This means that they are only visible within the translation unit they are compiled from. To this end, if you are creating a template class or function that you want to be callable from multiple source files, you must put the declaration *and* definition into a header file. The header file will be included within each translation unit as-needed, and so your template functionality will be accessible. This is complicated a bit by the fact that Visual Studio has a language extension that creates external linkage template definitions from source files, so you may not have noticed this if you’re on Windows.
However, there’s an interesting problem that crops up from this requirement. If you wish to specialize a template function, you must do it at namespace scope (so you can’t do it within a class declaration). So how do you do this properly? You define the function out-of-line with the class, but within the same header file. Like this:
class Foo { public: template <typename Ty> void Bar( Ty ) { // Do something } template <> inline void Bar<int>( int ); }; template <> inline Foo::Bar<int>( int ) { // Do something }
The tricky part is the inline keyword. Without it, you will get linker errors if you attempt to #include your header file from more than one source file. Without the inline specifier, the compiler would create a definition of Foo::Bar in each translation unit, which would lead to multiple symbols of the same name in different object files. The linker wouldn’t know which one to pick! But by using the inline specifier, the compiler knows to create only a single definition of Foo::Bar to be shared amongst all translation units. This behavior isn’t specific to template specializations either — you’ll run into the same problem with any out-of-line definition within a header file.
25 : C++
Empty Classes
Did you know that empty classes still take up space? Imagine:
class Foo {}; Foo f[ 10 ]; // How much space does f require? ::printf( "%d\n", sizeof( Foo ) ); // What would this print?
Arrays are just pointers, and C++ does not like pointer math with objects requiring no space because all sorts of operations would stop making sense. So the standard works around this by allowing compilers to allocate whatever space they require for empty classes. Most compilers simply treat empty classes as being 1 byte in size. However, there is an exception to this rule: base classes. The standard allows an empty base class to take up no space. This is known as the “empty base class optimization” and is something library writers exploit frequently when dealing with type traits and other template tricks. Since these empty base classes take up no space, the compiler can easily inline all the base class functionality directly into the subclass. So the programmer gets a cleaner class hierarchy, but doesn’t suffer a penalty for doing so.
26 : C/C++
Oddly enough, the C and C++ standards don’t require ASCII as the basic execution character set (for instance, EBCDIC could be used). The only hard requirements set by the standard are that there be a null character (or corresponding wide character) whose value is 0, and that each numerical digit is always one greater than the previous digit.
This leads to some rather entertaining standards-compliance minutiae. For instance:
bool isDigit( char c ) { if (c >= '0' && c <= '9') { // Legal return true; } return false; } int getDigit( char c ) { if (isDigit( c )) { return c - '0'; // Legal } return -1; } bool isLowercaseAlpha( char c ) { if (c >= 'a' && c <= 'z') { // Non-standards complaint! return true; } return false; }
It may seem strange, but you can see for yourself in [lex.charset]p3 of the C++ standard, or 5.2.1p3 in the C standard! So if you want to be a compliance guru, always use the built-in library calls from ctype.h (such as isalpha and friends) to do this sort of trickery, with the exception of dealing with nulls or numeric digits.
27 : C/C++
Templates can be tricky! This example came up recently as a “what’s going on here?” with one of our projects.
template <typename Ty> class base { public: void foo(void) {} }; template <typename Ty> class sub : public base< Ty > { public: void bar() { foo(); } };
If you run this code, you should receive a compile error for your troubles with the call to base< Ty >::foo — it won’t be found by the compiler! The reason is spelled out in the standard at [temp.dep]p3: “In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.”
In short, this means that you need to use a qualified name in order to call foo. Either this->foo() or base< Ty >::foo will suffice. It seems that some versions of gcc have a bug where they allow you get away with some instantiations of the template, and MSVC always allows it (likely due to its positively bizarre delayed template parsing) and clang happily points it out so long as you instantiate the template somewhere. So you may not always notice this issue right away, depending on the compiler and version you’re on.
In case you think this is something which doesn’t affect us: Scot came to me with this very quandary because it cropped up in our production code when upgrading compilers. The previous version had a bug in it where the unqualified name lookup ignored the standard, and the newer version fixed that bug.
28 : C++
Character Widths
In C++, sizeof( char ) == sizeof( ‘a’ ), and sizeof( wchar_t ) == sizeof( L’a’ ), which seems fairly sensible. But did you know that it doesn’t hold true for C? In C, all character literals (wide or otherwise) are ints! So in systems where CHAR_BIT == 8, sizeof( char ) is 1 and sizeof( ‘a’ ) is 4. What’s more, in C, wchar_t is a typedef instead of a first-class datatype. So stddef.h determines what sizeof( wchar_t ) will return, whereas L’a’ will always return an int.
29 : C
Type Variance
With polymorphic objects, there are three main type system comparison concepts of interest in a programming language: covariance, contravariance and invariance. Covariance is when you take a wider type and make it narrower. Contravariance is when you take a narrow type and make it wider. Invariance is a type that is neither covariant nor contravariant.
class B {}; class C : public B {}; class D {};
If you convert from B to C, it is covariant because C is a narrower type than B. If you convert from C to B, it is contravariant because B is a wider type than C. D is invariant with regards to B and C because there is no relationship between them. “Converting” from C to C is also invariant because it is neither narrower nor wider.
Why is this interesting? It allows a virtual function in a subclass to return a more narrow object, but still satisfy the signature requirements for the method. Eg)
class B { public: virtual B *foo(); }; class C : public B { public: virtual C *foo(); };
C::foo is a covariant version of B::foo since it returns a more narrow type, and thus is a legal override. This allows you to write code like this:
C *c = new C(); C *c2 = c->foo();
If covariant return types were not allowed, you would have to use dynamic_cast to convert B * into a C * when calling foo because C::foo would have to return a B * just like B::foo.
Interesting aside: C++ allows covariant return types, but C# does not allow them, and Java only partially allows it.
30 : C++
Template Typedefs
We’re all aware that typedefs are a great way to create an alias type in C++. We can name items more succinctly, especially when names get unwieldy. For instance:
typedef std::map< SomeAwesomeClass, SomeOtherClass > MyMap;
However, one thing you cannot do is create template typedefs. Say you want to use a std::map where you specify one of the template types, but not the other. Trying this in C++ will fail:
template <typename Ty> typedef std::map< SomeAwesomeClass, Ty > MyMap; // Error!
One of the new features of C++11 is an alternate syntax to typedefs which rectifies this situation. You can use the using statement to create template typedefs, as well as regular typedefs.
template <typename Ty> using MyMap = std::map< SomeAwesomeClass, Ty >; // Legal! using MyOtherMap = std::map< SomeAwesomeClass, SomeOtherClass >; // Legal!
Now you can use MyMap and MyOtherMap in the fashion you’d expect:
int main( void ) { MyMap< int > m; MyOtherMap m2; return 0; }
31 : C++
Range-based For Loops
I’m a pretty big fan of terse but maintainable code because I firmly believe the best code we write is the code we don’t write at all. So the range-based for loop functionality in C++11 is a feature I especially love. It can be used with any array, or any type for which begin() and end() can be called.
std::vector< int > v = { 1, 2, 3, 4, 5, 6 }; // New std::initializer_list constructor for (int i : v) { // Can use i in here, it will be v[0]...v[5] }
This is even nicer when used in conjunction with automatic type induction. No more massive iterator-declared for loops!
std::map< SomeBigNamedClass, SomeOtherBigNamedClass > m; // Old way for (std::map< SomeBigNamedClass, SomeOtherBigNamedClass >::const_iterator iter = m.begin(), end = m.end(); iter != end; ++iter) { } // New way for (const auto& p : m) { // can use p.first and p.second }
32 : C++
Name Visibility, Access Control and Overload Resolution
In C++, name visibility, access and overload resolution are separate concepts; they work together serially. First names are looked up, then overload resolution takes place, then access restriction takes place. This can make for some interesting situations that are not always obvious. For instance:
struct A { virtual void f(int); }; struct B : public A { void f(float); }; B *b = new B; b->f( 1 ); // What gets called?
First, names are looked up. Because B::f the same name as A::f, B::f hides A::f. So during name lookup, A::f is never seen which means that overload resolution never gets a crack at it. So B::f is called. The moral of the story here is: you cannot overload functions across a class hierarchy because overloading happens *after* name lookup, and name lookup does not consider signatures. You can, however, overload functions that do not cross a class hierarchy. If we add the following to B:
void f(int i) { A::f( i ); }
Then we get a different beast. First name lookup happens, which finds B::f(int) and B::f(float) (A::f is still hidden by the B::f names). Then overload resolution takes place, and finds B::f(int) to be the best viable function, so first B::f(int) is called, which then calls through to A::f(int). If we declared B::f(int) to be a private function, the behavior changes again. In this case, access restriction takes place and that removed B::f(int) from the candidate set, which is now empty and *no* function gets called. So keep in mind that these stages do not backtrack.
Given the above information, can you explain why this code behaves the way it does?
struct A { virtual void f(int) { ::printf( "A" ); } }; struct B : public A { void f( float ) { ::printf( "B float" ); } private: void f(int) { ::printf( "B int" ); } }; B *b = new B; A *a = b; a->f( 12 ); // prints "B int" a->f( 12.0 ); // prints "B int" b->f( 12 ); // error b->f( 12.0 ); // error b->f( 12.0f ); // prints "B float"
33 : C++
Assignment Operators
If you are going to override the implicit assignment operator (whether copy or move assign), you should consider making it virtual. I say “consider” because it truly depends on your class. If you expect your class to be subclassed (so you have virtual functions somewhere in the class), then making the assignment operator virtual is a very sensible idea. It allows the subclass to then implement its own assignment operator which gets properly called in dynamic situations. But if you do not expect your class to be subclassed (you have no virtual members and there’s little chance for specialization), then don’t make your assignment operator virtual since it adds overhead for no gain.
The flip side of this is when you add an assignment operator to a subclass. Be sure to check the behavior of the parent class to determine how to proceed. You may need to add a call to TheBaseClass::operator= from your assignment operator in order for the assignment to complete properly.
34 : C++
Polymorphism in Constructors and Destructors
Never (ever!) use dynamic class information from within a constructor or destructor, because the behavior is undefined (or unobvious). This means you should not use dynamic_cast, typeid or call virtual functions on the “this” object. Eg)
class C { public: C() { foo(); // Bad idea! SomeCDerivative *t = dynamic_cast< SomeCDerivative * >( this ); // Bad idea! typeid( C ); // Bad idea! bar(); // Perfectly acceptable } virtual void foo() {} void bar() {} };
If you use an object dynamically from within the constructor, you can run into problems ranging from outright crashes (such as accidentally calling a pure virtual function) to misapplied function calls, to things just happening to work by chance with the current class hierarchy. Trust me, it’s best to avoid doing this, as the bugs can be a real pain to track down!
35 : C++
Delegating Constructors
One of the handy new features in C++11 is the concept of a delegating constructor, where one constructor is allowed to delegate some functionality to another constructor. This greatly reduces the need for duplicate code in your constructors, allowing you to write code that is more easily maintained. For instance:
class C { int i; double d; const char *str; public: C( int i_, double d_ ) : i( i_ ), d( d_ ) {} C( int i_, double d_, const char *str_ ) : C( i_, d_ ) { str = str_; } };
The downside is that when you delegate to another constructor, your initializer list can *only* contain the delegation. So you cannot initialize str as part of the initializer list in the second constructor. This may seem silly, but imagine a class like this:
class D { public: D() { // do something } }; class C { D d; int i; float f;; public: C( int i_ ) : i( i_ ) {} C( int i_, float f_ ) : f( f_ ), C( i_ ) {} // illegal! };
If this were allowed, D::D would be called *twice* under the rules of C++ class initializers. First it would be called for C::C( int, float ) because d is not explicitly initialized (so it would be default initialized, which would call D::D), then it would be called again for C::C(int) for the same reason. Invoking the constructor twice would be bad because objects can’t be constructed *twice*, and invoking the destructor in between constructors would be unobvious and possibly dangerous.
If you have constructors which perform a lot of initialization functionality that you share between constructors, you no longer need to put it into an Init method somewhere. Now you can delegate the functionality from one constructor to another, reducing the need for extraneous methods or duplicate code.
36 : C++
Better Living Through unique_ptr
One of the other nice features of C++11 is the std::unique_ptr class from . This is a replacement for the deprecated (and broken) auto_ptr class that allows you to have an efficient, guaranteed unique pointer that is used as a value type. Basically, think of it as a stack-based type that holds a heap-based pointer — you get all of the benefits of value semantics (automatic cleanup when the variable goes out of scope) as well as the benefits of pointer semantics (efficiency) and clear ownership without all of the memory leaks. You use it like this:
std::unique_ptr< some_type > ptr( new some_type );
You are able to use ptr like you would any other pointer type because it overloads the pointer operators to give you access to the underlying pointer. The only thing you can’t do with it is make copies of it, which is a great blessing. It means you have a very clear ownership strategy for the memory. Once ptr goes out of scope, it calls delete on the contained pointer. If you find the ownership semantics to be a bit onerous, you may want to rethink the design decisions surrounding the pointer because sharing pointers complicates code greatly.
So what if you want to use a pointer that doesn’t use delete, such as a pointer you get from malloc? Or a pointer-like type such as a Windows HANDLE object? No problem! With a bit of help from C++11’s decltype expressions and typedefs you can create aliases to unique_ptr that fit your needs:
typedef std::unique_ptr< void, decltype( &::free ) > unique_ptr_malloc; unique_ptr_malloc foo( ::malloc( 1000 ), ::free );
Or if you prefer to be really C++11 savvy, you can take advantage of the new using syntax (I talked about this in Tidbits #31):
using unique_ptr_handle = std::unique_ptr< void, decltype( &::CloseHandle ) >; unique_ptr_handle foo( ::CreateEvent( NULL, FALSE, FALSE, NULL ), &::CloseHandle );
I would highly recommend *everyone* make use of std::unique_ptr whenever they have the opportunity to do so. It’s safer than std::auto_ptr (and way safer than naked pointers), and is a very clean way to work with pointers in C++.
37 : C++
Override and Final
One of the other things I am a big fan of is making the compiler enforce my intentions. This is why I’m so keen on using const-correct code — the compiler will point out my mistakes instead of finding them later via a QA process. One handy new C++11 feature that enforces intentions are the override and final keywords on virtual method declarations. Consider the following code:
class B { public: virtual void foo( int ) {} }; class C : public B { public: virtual void foo( float ) {} };
The intention of C::foo may have been to override B::foo. Or it may have been to hide B::foo. There’s just no way to know. However, in C++11 you can be more explicit about your intentions by declaring C::foo using the override keyword.
class C : public B { public: void foo( float ) override {} };
Now you will get a compile error with the code because C::foo does not properly override B::foo. Similarly, as a class designer, you may not want a method to be overridden. Now you can specify the final keyword in the base class to prevent this.
class B { public: virtual void foo( int ) {} }; class C : public B { public: void foo( int ) final {} }; class D : public C { public: void foo( int ) {} // Error! };
So while override and final are not explicitly required to write correct code, I treat them much the same way as I treat the explicit keyword — it saves me from myself!
38 : C++
Deleted and Defaulted Functions
Along the same lines of enforcing intentions are explicitly defaulted and deleted functions. This is another feature that is new to C++11 that I really like to use when appropriate. They are a shorthand notation allowing you to tell the compiler whether a special member function should be implemented by the compiler (defaulted) or whether their use is explicitly not allowed (deleted). For instance, say you have a class:
class C { public: C(int) {} };
If you attempt to create an instance of C using the default constructor, it will fail because C’s implicit default constructor isn’t implemented by the compiler. However, instead of writing C::C() {} yourself, you can use default to do it for you:
class C { public: C() = default; C(int) {} };
This tells the compiler “go ahead and implement this constructor the way you would normally do it for me.” You can use this same notion to tell the compiler “this functionality is not allowed” and get a fantastic error message back. For instance, say you have a class that stores a pointer as a member variable, and you want to disallow copying of the class to keep ownership semantics sensible. Normally, you’d make a private, unimplemented copy constructor and assignment operator to do this. But with C++11, you can use deleted methods.
// Old way class C { // Not implemented anywhere! C( const C& ); C& operator=( const C& ); public: C() {} }; // New way class C { public: C() = default; C( const C& ) = delete; C& operator=( const C& ) = delete; };
With the old way, if you accidentally use the assignment operator with a C, you will get obscure linker errors talking about unimplemented methods. But with the new way, the compiler will tell you that you are using an explicitly deleted method. This is much nicer because you’re not left wondering if the omission was intentional or not.
Null Pointer Checking with new/delete
Can you spot anything odd with this code?
// Assume there is a class Foo somewhere with the proper constructor & methods Foo *f = new Foo; if (f) { f->DoSomething(); f; }
This code is doing more work than it needs to. In C++, the default operator new implementation will never return null. Instead, it will throw a std::bad_alloc exception! So the if (f) is not needed — if the call to new were to fail, the subsequent lines would never be executed anyway. What’s more, the call to delete f does not need to be wrapped in an if (f) block either. The operator delete must always handle the case where it is passed null by doing nothing. Note that the same is true of operator new[] and operator delete[].
If you want to perform an allocation which returns null instead of throwing an exception, you can use the placement new operator and pass in std::nothrow, like this:
Foo *f = new (std::nothrow) Foo; if (f) { f->DoSomething(); // Should be wrapped in the if block since f could be null delete f; // Doesn't need to be here, but doesn't hurt either }
Don’t write more code than you have to! You can remove if-null checks after your calls to new and before your calls to delete and your code will still be correct.
C++ : 40
SFINAE
One of the more powerful features of C++ are templates, and one of the more powerful template features is SFINAE (which, when coupled with RAII, demonstrate why languages people should never name things). SFINAE stands for “Substitution Failure Is Not An Error”, which basically means that the compiler is free to ignore errors in template methods so long as it can locate something legal as a replacement. Eg)
template <typename Ty> typename Ty::result_type negate( const Ty& val ) { return -val(); } template <typename Ty> Ty negate( const Ty& val ) { return -val; }
If you were to call negate( 12 ), the first function definition would effectively read:
int::result_type negate( const int& val ) { return -val(); }
Since int does not have a member named result_type, and int cannot be used as a function call, this definition would produce an error. The second definition would effectively read:
int negate( const int& val ) { return -val; }
This is a perfectly legal function definition and would be viable to call. So when the compiler goes to compile negate( 12 ), it skips the first definition without emitting any diagnostics, and selects the second one. SFINAE is an integral part of working with templates for non-trivial cases; it is heavily used in the STL implementation.
C++ : 41
Abstract Base Classes
As C++ programmers, we’ve all encountered the notion of pure virtual functions as the way to create something akin to interfaces. However, they bring up a rather interesting edge case in language pedantry. Consider the following code:
class iface { public: virtual void foo() = 0; }; class bar : public iface { public: ~bar(); void foo(); }; iface *ptr = new bar; delete ptr;
What happens at the call to delete? Technically, a bug! Calling delete on a polymorphic base class pointer when the base class does not define a virtual destructor is undefined behavior (as per [expr.delete]p3). So what is the correct way to do this? There are two answers, one of which is likely a surprise to you:
// Way 1 class iface { public: virtual ~iface() {} virtual void foo() = 0; }; // Way 2 class iface { public: inline virtual ~iface() = 0; virtual void foo() = 0; }; iface::~iface() {} // I lied, there's a Way 3 class iface { public: inline virtual ~iface() = 0 virtual void foo() = 0; }; iface::~iface() = default; // C++11 feature
The first way is probably obvious enough in that it defines a virtual destructor implementation in the class. But did you know that the other way was even possible? In fact, it is possible *and useful in some circumstances*! When you declare a destructor in your class, you *must* define it (or else run into linking errors), and it is perfectly valid to define an implementation for a pure virtual function. Way 2 and Way 3 are moral equivalents of the same thing — they declare a pure virtual destructor, and they turn around and define an implementation for it (note: if your class lives in a header file, you need to declare it inline virtual and put the definition within the header file). However, there is no true benefit to any of three examples — they all do the same thing under the hood (they’re all basically default implementations of a destructor). The moral of the story here is: *always* define a virtual destructor in your abstract base classes! Failing to do so is a subtle bug.
But why would I bring up Way 2 or Way 3 if they’re not any better than Way 1? Simple — if you want to make an abstract base class with no other pure virtual functions (perhaps all the other virtual functions have concrete implementations), Way 2/3 are the way to go. If you declare the destructor as pure virtual in the base class, then no one can create an instance of the base class directly; they must go through a concrete subclass. This avoids having to come up with a “fake” pure virtual function that you don’t actually want to have in the first place.
C++ : 42
Translation Units
In C and C++, all source code is seen by the compiler as “translation units.” The way translation units are structured is quite simple: take a single source file and start scanning it. Every time you see a #include, replace it with the contents of the file being included, and start scanning that. Eventually, what you end up with is a single source file representing the entire translation unit. That is then compiled down into an intermediate form (such as a .obj file), and all of those intermediate forms are sent off to the linker to be mashed back together into a single executable.
Why is this important? Because of the #include part! You should be very careful when adding #include files to your source code, especially within header files. If you’re not careful, you can wind up making your compile times ridiculously long for no real gain because the compiler has to continually slurp in unused headers. Consider the following:
// File.h #include <string.h> #include <stdio.h> void foo( void ); // File.cpp #include "File.h" void foo( void ) { ::printf( "Haha\n" ); } // main.cpp #include "File.h" int main( void ) { foo(); return 0; }
When the compiler gets File.cpp, it grabs the contents of File.h. Then it starts processing File.h, and it grabs string.h and stdio.h, respectively, and grabs those contents. The end result is that File.cpp compiles fine. However, *nothing* in File.h actually requires string.h or stdio.h in order to compile properly! So when the compiler goes to compile main.cpp, it grabs File.h and does the same grabbing steps as before — except now main.cpp has to compile *everything* from string.h and stdio.h, except nothing in main.cpp uses those headers. Better form would be to remove the includes from File.h, and put them in File.cpp (and remove the include for string.h since it is not used for anything). This way, main.cpp doesn’t need to do all that extra compilation work.
Bonus question: why is it important to use standard header include guards in C and C++ header files?
C/C++ : 42
Iterators
We’ve probably all written code that looks something like this, without thinking twice about it:
void something( const std::vector< blah >& stuff ); void something_else( blah *stuff, size_t count ); // etc
But I’d like to take a chance to think twice about whether that’s really a good way to do things. While this style of code certainly works, it does have a problem in that it causes too tight of coupling between the caller and the callee. The *only* thing you can pass in for the first call is a vector. The *only* thing you can pass in for the second call is something expressible as an array. Oftentimes, this tight of coupling is not actually required by the callee — it just needs a generic list of stuff. A better approach would be to use the notion of iterators:
template <typedef Iter> void something( Iter start, Iter finish ) { for (; start != finish; ++start) { blah& b = *start; yada( b ); } }
By using an iterator, you’re now allowing for different list data structures to be used as appropriate, so you can still use a vector, or an array if you’d like. But you can also use a set, or a queue, etc. This better encodes the underlying purpose of the code without putting as much emphasis on the “how” (it emphasizes the “what” instead), and in turn, this makes refactoring jobs considerably easier in the future.
This has an extra benefit that might not be readily obvious: it will work with anything which can be represented as a blah, whereas the original code would only work with a concrete blah object itself. Consider:
class bing { public: operator blah() const { return convert_to_blah(); } };
The first code would fail if passed a vector/array of bing objects, but the second code would still function appropriately. If you really wanted to ensure that you got *only* a blah object, you could use std::is_same from type_traits along with a static_assert to provide good error messages.
C++ : 43
RAII Objects
Another terribly-named but incredibly powerful concept in C++ is RAII: Resource Acquisition Is Initialization. Sounds a bit odd, but it is a core principle of C++ instead of just a happy accident. In order for you to reach the initialization stage of construction, your resource is fully allocated. And the only guarantee you have when exceptions are thrown is that stack-based object destructors will be called. This bracketing proves to be an incredibly powerful utility because it gives you a clear ownership strategy for work that is exception-safe. Oftentimes, it can be used to clean up code that is littered with “if failure then cleanup” code because of the assurance that stack-based destructors will fire. As a contrived example:
FILE *f = ::fopen( "some_file.txt", "w" ); if (!f) return; if (!write_something( f )) { ::fclose( f ); return; } if (!write_something_else( f )) { ::fclose( f ); return; } if (!write_more_things( f )) { ::fclose( f ); return; } ::fclose( f );
If we wrap the FILE object in an RAII class, then we can skip a lot of brackets and fclose calls. Eg)
class file { FILE *mFile; public: file( FILE *f ) : mFile( f ) {} ~file() { ::fclose( mFile ); } }; FILE *f = ::fopen( "some_file.txt", "w" ); if (!f) return; { file hold_( f ); if (!write_something( f )) return; if (!write_something_else( f )) return; if (!write_more_things( f )) return; }
I realize that my example is rather contrived, but I am sure we’ve all seen code with dozens of if statements, all with resource releasing in failure cases. You can probably imagine how much more clean the code would be if all of those release statements could be removed — and you can also imagine how much safer the code is to modify, since you don’t have to track resource state information!
When you find yourself working with objects that have a definitive “open” and “close” pattern to them, you should strongly consider whether an RAII object might make sense, and whether one already exists that solves the problem for you. In the case of FILE *, you could use an STL stream object; many pointers can be handled with STL’s unique_ptr class, etc.
C++ : 44
Integer Division
Integer division has a pretty nasty piece of implementation-defined behavior you may not be aware of. When dividing two positive integer values, or two negative integer values, the behavior is well-defined. But when dividing a positive and a negative integer value, the compiler can do one of two things. It may round up with a negative remainder, or it may round down with a positive remainder. For instance, -5/3 can either be -1 with a remainder of -2, or it could be -2 with a remainder of 1.
It just so happens that MSVC, gcc and clang all agree that the value is -1 remainder -2, but you may not have even been aware the answer could be different!
C/C++ : 45
Parameter Evaluation Order
Here’s a contrived question for you; what gets printed from the following code?
int foo() { extern int x; return ++x; } int bar() { extern int x; x *= 2; return x; } int quux( int a, int b ) { return a + b; } // Assume extern int x = 10; ::printf( "%d\n", quux( foo(), bar() ) );
The correct answer is “who knows!” In C and C++, the order that formal parameters are evaluated when calling a method is mostly undefined. I say mostly because there is some definition, but not enough that is useful here. So you wind up with one of two execution paths. Either foo() could be called first, at which point you wind up with (11) + (22), which is 33; or bar() could be called first, at which point you wind up with (21) + (20), which is 41.
The only real guarantee you have when passing parameters is that all of the parameters will be evaluated before being passed into the method. So you know that foo and bar will both be called before quux is called, but you can’t be assured of any particular order for any compiler. The moral of the story here is: be very careful of functions with side effects. If your functions don’t have side effects or don’t rely on external (global) state, you are fine. But if your functions do have side effects, you should use temporary values instead of calling the functions inline. Eg)
int a = foo(), b = bar(); ::printf( "%d\n", a, b );
This will assure you of the order that functions are called.
C/C++ : 46
Hex Floating-Point Literals
A random, little-known feature of C99 is the hexadecimal floating-point literal. printf( “%g\n”, 0x1.AB2Cp12 ); The 0x designates that it’s a hex literal, and the p (or P) is the exponent designator. The way you read it is: 1.AB2C * 2^12 = 1.1010101100101100 * 2^12 = 1101010110010.1100 = 6834.75
So why is this interesting? Because decimal floating-point representations can be rounded when expressed since they are just approximations — but hexadecimal floating-point representation is the same way the numbers are laid out in memory. Basically, you normalize the value and then represent it by: sign * 2 ^ exponent * mantissa. In the case of 6834.75, the value can be represented exactly, but this is not always the case with all values. By allowing you to use hexadecimal floating-point values, you can control exactly how a value is represented to prevent rounding errors with the constant itself. It’s not likely that you’ll be using this every day, but if you need more exact representations of floating-point constant values, this is the way to do it.
Note that MSVC does not let you use hexadecimal floating-point literals, but gcc and clang do (so long as you are compiling with C99 support enabled).
C/C++ : 47
When to Specify virtual
When inheriting a class that contains virtual methods, you do not need to redeclare the subclass methods as being virtual. This is implied by the base class methods and cannot be changed by subclasses. For instance:
class Base { public: virtual void Foo() {} }; class Subclass : public Base { public: // Incorrect virtual void Foo() {} // Do *NOT* need to specify virtual here! // Correct void Foo() {} // It's already virtual! };
The only notable exception to this rule is with destructors. If your class has any virtual methods, you should *always* give it a virtual destructor, even if it’s trivial! In the examples above, Base needs a virtual destructor, and so does Subclass! This is because the defaulted destructor created for you by the compiler will *not* be virtual, and so you can have hard to track down memory leaks from destructors not being called properly!
Just to be clear, there’s no *harm* in declaring as virtual in the subclass. It’s purely a matter of whether you find it to be more or less readable for maintaining the class hierarchy.
C++ : 48
Const-Correct Methods
What does it mean for a method to be const-correct? The answer might surprise you somewhat because it doesn’t strictly mean “cannot mutate the class instance.” A const-correct method cannot mutate the externally-visible parts of a class. It’s a subtle difference, but one that pops up from time to time. Consider the code:
class c { ExpensiveLookupTable mTable; public: Thing do_expensive_lookup( const Key &key ) const { return *(mTable.lookup( key )); } void insert( const Key &key, const Thing& thing ) { mTable.insert( key, thing ); } };
The do_expensive_lookup method performs a slow lookup in the lookup table, but it doesn’t mutate any state. But what if we wanted to cache our lookup? Our code might change to something like this:
class c { ExpensiveLookupTable mTable; TinyLookupCache mCache; public: Thing do_expensive_lookup( const Key &key ) const { iterator iter = mCache.lookup( key ); if (iter != mCache.end()) return *iter; iterator expensive_iter = mTable.lookup( key ); mCache.insert( key, *expensive_iter ); return *expensive_iter; } void insert( const Key &key, const Thing& thing ) { mTable.insert( key, thing ); } };
So now, we perform the lookup in a fast cache table, and if that succeeds, we return the data. But if it fails, we perform the lookup in the expensive lookup table, but cache the results before returning them. However, this code wouldn’t compile because mCache.insert mutates the mCache variable, which cannot be done from a const method. If you squint your eyes a bit, you’ll notice the fact mCache even exists is never exposed to the user — it’s ancillary. (Consequently, you cannot make the same argument for mTable because that’s a primary member of the class.) We just happen to use mCache to support the lookup operation. So in this case, C++ has the mutable keyword; it effectively allows the compiler to ignore the constness of a method, allowing you to mutate that particular variable. Eg)
mutable TinyLookupCache mCache;
You won’t use the mutable keyword that often when writing a const-correct method, but it does come up from time to time. Most often you will see it used with caching, but another very common usage is with threading locks. Eg)
int some_instance_method() const { ::EnterCriticalSection( &mLock ); int ret = get_something_critical(); ::LeaveCriticalSection( &mLock ); return ret; }
In order for that code to compile, you would have to declare mLock as being mutable if it was a member of the class instance.
C++ : 49
Lambda Functions (Part 1)
C++11 has a fantastic new feature called “lambdas” that you may be familiar with from other languages such as JavaScript, Python and C#. A lambda is a fancy way of saying “anonymous function” — it’s a function you create on the fly, and assign into a variable for use later. The syntax in C++11 looks like this:
[]( int i ) { ::printf( "%d\n", i ); };
The [] is called the “lambda introducer”, and is used to specify 1) that you are defining a lambda expression, and 2) any variables you would like to capture from the surrounding environment (more on this later). The () is the parameter list for formal arguments to be passed to the function. The {} is the body of the lambda (the code to be executed).
The example above doesn’t do much because it defines the lambda, but there’s no way to call it. It’s morally equivalent to code like:
12;
aka, perfectly legal and totally useless. Because lambdas are anonymous functions, they make an anonymous type (much the same way that anonymous unions do), so in order to assign them into a variable, you need to use the new auto keyword. Eg)
auto fn = []( int i ) { ::printf( "%d\n", i ); }; fn( 12 ); // Prints 12 fn( 14 ); // Prints 14
C++ : 49
Lambda Functions (Part 2)
I wrote earlier about capturing information from the surrounding environment. Lambdas in C++11 are also closures — they can “close” environment information into the lambda function, allowing you to make use of it later. You can specify what information to store in the lambda introducer:
int i = 12; auto fn = [i]() { ::printf( "%d\n", i ); }; fn(); // Prints 12 i = 100; fn(); // Prints 12
By default, lambdas do not capture anything from the environment. But you can specify a list of individual variables to capture and how to capture them, or be more general and specify to capture “everything.” You can use = to capture all variables by value, & to capture all variables by reference, or this to capture all class member variables. Eg)
std::vector< int > g; int f = 10; auto fn = [&g, f]() {}; // Captures g by reference, f by value auto fn2 = [=]() {}; // Captures both g and f by value auto fn3 = [&]() {}; // Captures both g and f by reference auto fn4 = [f,&]() {}; // ERROR: you can't specify both specific variables and = or & auto fn5 = [f, this]() {}; // Captures f and all of the current class' member variables
Capturing by value behaves the same as you would expect when passing a parameter by value. It will create a copy of the item when capturing it. Capturing by reference behaves the same as well — it will not create a copy, but instead create a reference. When you capture the this pointer, you are basically importing the “this” pointer for purposes of lookup operations, so you are capturing the this pointer by value (but since it’s a pointer and not a value type, no copies are made of the class).
There are some things you should be careful of when adding capture items. Namely:
* Capturing by reference allows you to modify the value within the lambda and have the effects seen outside of the lambda. But it does not extend the lifetime of the object! So if you capture by reference and the value being captured goes out of scope, you have a dangling reference.
* Using the catch-all captures will always capture more than you anticipate and should be avoided. For instance, it captures global variables too!
C++ : 50
Lambda Functions (Part 3)
In order to truly understand lambdas in C++11, you should understand what functionality they replace. If you’ve ever used advanced functionality in the STL such as items from , you’ve likely encountered “functors”, which are function objects. Lambdas are just short-hand for functors — there’s a one-to-one relationship between the two. Here’s an example demonstrating their equivalence:
// As a lambda int i = 10, j; auto fn1 = [i, &j]( int k ) { ::printf( "i: %d\nk: %d\n", i, k ); j = 100; }; fn1( 20 ); ::printf( "j:%d\n", j ); // As a functor int i = 10, j; struct functor { private: int i, &j; public: functor( int i_, int& j_ ) : i( i_ ), j( j_ ) {} void operator()( int k ) const { ::printf( "i: %d\nk: %d\n", i, k ); j = 100; } }; auto fn2 = functor( i, j ); fn2( 20 ); ::printf( "j:%d\n", j );
Given this information, you should be able to explain why the following code doesn’t compile:
int i = 10; auto fn = [i]() { i = 12; };
This is because lambdas are constant methods by default. However, you can create a non-const method by using the mutable keyword in the declaration:
int i = 10; auto fn = [i]() mutable { i = 12; }
This is not something you are likely to use often simply because you want to mutate a captured variable (after all, since it was not captured by reference, the change will not be visible outside of your lambda function), but it is something you’re more likely to use if you want to make a lambda that can call non-const class member variables. Eg)
class c { public: void foo() {} void bar() { auto fn = [this]() { foo(); } // Error because foo is non-const auto fn2 = [this]() mutable { foo(); } // Okay } };
C++ : 51
Lambda Functions (Part 4)
Why would you want to use lambda functions in your own code? Because they work wonderfully in place of function pointers for those times when a full-on delegate class is overkill. The STL is a fantastic example of such usage — when you want to call std::copy_if, you don’t need to create an entire functor yourself, nor do you need an externally-visible predicate function. Instead, you can dash off a quick lambda to do the work for you. But this begs the question of how to properly use a lambda in your own code? You’ve already seen that you can assign a lambda into a local variable using the auto keyword. But what if you want to pass that lambda to another function? Templates!
template <typename Func> void foo( Func fn ) { fn( 10 ); } foo( []( int i ) { ::printf( "%d\n", i ); } );
Because lambdas are anonymous types, using templates is a great way to pass them around as parameters and retain the type safety. If your lambda doesn’t meet the function requirements, you will still get a diagnostic telling you about it. You should prefer using templates to alternatives like function pointers (lambdas only safely convert to a naked function pointer if they do not capture anything), or std::function (std::function can’t handle things like type coercion and so are not as flexible).
C++ : 52
Lambda Functions (Part 5)
When most people think about using lambdas, they think about function callbacks, functors, etc. But here’s another great use of lambdas that’s not quite so obvious. Have you ever written code that does the following:
int i = some_default; if (something) { i = compute_new_i(); } // Do something with i where i is always const
Good programming practice would suggest you want i to be marked as const so that no one can accidentally assign into it. However, there’s no way for you to actually mark i as const because the if (something) block is assigning into i. Thank goodness for lambdas! The generally-accepted-but-little-known pattern for this is:
const int i = [&] { int i = some_default; if (something) { i = compute_new_i(); } return i; }();
The () at the end of the lambda invokes it immediately, and so const int i is initialized with whatever calculated value of i we came up with. This allows you to preserve const-correctness while making safer code and looks awfully similar to our original code while doing it!
C++ : 53
Unaligned Memory Access
What gets printed with the following code?
#pragma pack( push, 1 ) struct s { char c; int i; }; #pragma pack( pop ) void f( int *i ) { *i = 12; } struct s s1; s1.c = 'a'; f( &s1.i ); ::printf( "%c, %d", s1.c, s1.i );
The correct answer is: it depends! The problem is one of alignment. In C and C++, dereferencing unaligned memory is undefined behavior. In the best case, the code will simply run slowly and print ‘a’ and 12. But what can frequently happen are crashes depending on the hardware. Some architectures (namely RISC ones like ARM and PPC) will always crash. Other architectures are hit and miss, like x86 — you can find systems that crash as well as ones that just access the memory slowly.
The safest course of action is to not perform unaligned memory access. For the code above, it would be better to write it like this:
struct s s1; s1.c = 'a'; int temp; f( &temp ); s1.i = temp;
In this case, all memory access is aligned and there are no problems. Alternatively, you could use byte-wise addressing where the alignment is expected to be on a one-byte boundary, eg) memcpy.
C/C++ : 54
Floating-Point Equality
Testing for floating-point equality is a dangerous affair due to the approximation of values. There are ways around this involving “fuzzy” equality testing. You can use an epsilon in the comparison so you can say the two values are “close enough”, which only works if the magnitude of the two numbers is reasonably small. Eg)
float x, y; // Set somewhere else if (x == y) {} // WRONG! if (::fabs( x - y ) <= std::numeric_limits< float >::epsilon()) {} // RIGHT!
This works well if you want to detect tiny differences between x and y (technically, the epsilon is defined as the smallest representable difference between two numbers — aka, the step between them). If larger differences are acceptable for equality testing (perhaps you are comparing the distance between two stars), then you can create your own epsilon based on what’s acceptable for your needs.
C++ : 55
Great collection of important and useful gotchas. I wish you’d put them as individual blog posts so the world can converse with you on each one separately. And who says blog posts need to have the weight of an article?
Thanks! Interesting idea to push them off into separate pages — I assumed it would start to look kind of spammy, but the size of the tidbits page is getting a bit unwieldy these day. I’ll look into it!
#10 : C++
Object Slicing
I think the vector_free should be:
template
void vector_free( void *memory, unsigned count ) {
unsigned char *ptr = ((unsigned char *)memory) + (sizeof( T ) * count – 1); //1
while (ptr >= memory) {
((T*)ptr)->~T(); //2
ptr -= sizeof( T );
}
free( memory );
}
1. ptr should be off (count – 1) times sizeof(T) to get the last object
2. operator delete() wraps free(), here should call destructor instead
Ruiner: you are correct on both accounts. #1 was simply a bug on my part; #2 was attempting to demonstrate the destructor is called without resorting to showing manual destructor calls (which most people don’t know you can do). But I think correctness is better, so I’ve modified the example. Thanks for pointing it out!