Sunday, October 31, 2010

Namespaces

The following code does not compile:

  namespace A
  {
    static const int a = 1;
    namespace B
   {
      static const int b = 2;
      namespace C 
      {
        static const int c = 3;
      }
    }
  }
  int main() {
    using namespace A::B;
    return B::C::c;
  }


The using statement brings namespace B into scope. If you need to get to the 'c' symbol, you need to do either absolute addressing: A::B::C::c or relative addressing C::c. It is almost analogous to changing directories in Unix.

Template Specialization Warning

Say that you want to force a user to specialize a template that you have created, the following constructor would warn the user better:

   MyClass() {#error "This template needs to be specialized"}

Than

   MyClass() {This_template_needs_to_be_specialized;}

Most compilers will complain about the undefined symbol 'This_template_needs_to_be_specialized'. If you forget the ';', the compiler will focus on that error.

The #error statement is processed by the CPP (C Pre-Processor). This happens before the compiler sees any text. The preprocessor will fail the compilation in all cases when it sees this directive.

Forcing an explicit template specialization is sometimes very useful. It is analogous to a base class that has a pure virtual function, which makes the base an abstract class so that objects cannot be created from it. The abstract class specifies an interface for the derived classes to implement.

Saturday, October 30, 2010

Memory Alignment

Dynamically-allocated memory via new and malloc are guaranteed to be aligned properly for a machine, while non-dynamically-allocated memory is not. Where "non-dynamically-allocated memory" is automatic memory where objects are allocated on the stack using placement new on top of a char buffer. The char buffer may or may not be aligned, which can be a latent bug, or a cause of a problem when porting.

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, p. 117.

Argument Dependent Lookup (ADL)

Given the following program:

   #include <iostream>
   using namespace std;
   namespace A
   {
      struct A
      {
         int i;
      };
      void funcA(A a)
      {
         cout << "A::funcA" << endl;
      }
   }
   namespace B
   {
      void funcA(A::A a)
      {
         cout << "B::funcA" << endl;
      }
   }
   namespace C
   {
      void funcC()
      {
         A::A a;
         funcA(a);
      }
   }
   int main()
   {
      C::funcC();
      return 0;
   }


The following will happen:

A::funcA(A a) will be called. This is an example of Argument Dependent Lookup (ADL) also known as Koenig Lookup. If the compiler does not find funcA() in the current scope, it will look in the namespace where funcA()'s formal parameter was declared.

Reference: http://en.wikipedia.org/wiki/Koenig_Lookup

Friday, October 29, 2010

Function Hiding

When you declare a function, it hides all functions of the same name in all base classes, no matter if the function is public, private, or protected or even if it has a different signature.

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, p. 134.

Function Name Lookup

In function name lookup, once the compiler finds at least one function with the same name in a scope, it will not look any further; even if the function signatures do not match.

If none of the functions in the that scope has a matching signature, it will not look any further in any other scope; even in an outside scope with a match. Instead, the compiler will give an error.

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, pp. 134-135.

Thursday, October 28, 2010

Header Files

The C Standard specifies which standard header files include other standard header files; The C++ standard doesn't do the same thing.

This can cause portability issues. A typical issue is when a free operator+() is declared outside of the namespace that its associated class is defined, you may or may not get very long template error messages depending what standard C++ include files are included in other standard C++ include files.

Reference: Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions by Herb Sutter. Addison-Wesley, 1999, p. 137.

Interface Principle

According to the Interface Principle, functions that have signatures that mention objects of class X, and are in the same header file of class X, are part of the interface of class X, and should be put in the same namespace as class X.

This lets Koenig lookup do the right thing (most of the time).

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, p. 139.

Wednesday, October 27, 2010

operator new() and operator delete()

operator new() and operator delete() are static functions, even if you do not declare them as static functions.

It is recommended that you always declare them as static for maintenance purposes.

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, p. 146.

Resource Acquisition Is Initialization (RAII)

Resource Acquisition Is Initialization (RAII) is a technique to protect memory leaks and other kinds of resource leaks by wrapping construction of the memory/resource in an object that is automatically destroyed when it goes out of scope. auto_ptr<T> can be used to do this for dynamically allocated memory.

The header file used for auto_ptr<T> is <memory>.

Reference: http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

Tuesday, October 26, 2010

alloca()

Memory can be allocated off the stack at runtime using alloca().
alloca() is a C extension that allocates memory on the stack, typically by just moving the Stack Pointer down in order to allocate bytes. This can be used to allocate memory in exception-safe way (in some sense).

If an exception occurs, the allocated memory is automatically deallocated when stack frame is popped off the stack.

The second 'a' in 'alloca' stands for auto memory, which is the stack. alloca() is defined in the header file <alloca.h>. A corresponding <calloca> include file does not exist. alloca() is a C Language extension supported by many compilers. It was brought over into C++ on many compilers. It is not mentioned in the C++ standard. It's C++ functionality is implemented by the dynamic array feature. Here is a code example:

    void func(int size)
    {
        char * pMem = static_cast<char*>;(alloca(size));
        cout << "0x" << hex << reinterpret_cast<int>(pMem) << endl;
        #if 1
            char myArray[size];
            char * pMem2 = &myArray[0];
            cout << "0x" << hex << reinterpret_cast<int>(pMem2) << endl;
        #endif
    }

The code in the #if uses variable length arrays. Variable length arrays were intoduced in C99. Interestingly, alloca() works on g++, Sun C++, and IBM C++. Variable length arrays work on all of the above except Sun C++.

assert()

assert() is a macro that is sometimes used by 'Design by Contract (DoC)' programming, where code tests, preconditions, invariants, and postconditions.

assert() is defined in <assert.h> and <cassert>.

It is enabled via 'DEBUG' compiler macro and code #defines, and is disabled by the 'NDEBUG' compiler macro and code #define.

It is disabled by default.

The function basically asserts that the enclosed statement is true (or evaluates to a non-zero value).

When using asserts(), you want to make sure that you do not enclose any code that includes side effects, or else your code will behave differently depending on whether DEBUG is enabled or not.

Monday, October 25, 2010

auto_ptr<T>

When the current owner goes out of scope, the object that the auto_ptr is pointing to, is deleted by the auto_ptr<T>.

When a function returns an auto_ptr<T> by value, but the caller does not store the return value; The auto_ptr<T>'s object will be automatically deleted, so there will be no memory leak.

Reference: Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions by Herb Sutter. Addison-Wesley, 1999, pp. 154-155.

Const Autoptr<T>

A const autoptr<T> can never lose ownership of its contained pointer, unless you const_cast<>() the constness away.

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, pp. 159-160.

Sunday, October 24, 2010

Const

To the compiler, 'int func(int)' and 'int func(const int)' have the same signature.

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, p. 178.

Const

The following function declaration:
   void func(MyClass & const myClassObject);
is illegal, because of the 'const'.

The 'const' in the following declaration:
   void func(MyClass * const myClassObject);
is useless, because the pointer is passed by value, so the 'const' does not add anything.

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, p. 181.

Saturday, October 23, 2010

Member Variables

Inside a member function: a member variable, m_a, can be accessed as 'm_a' or 'this->m_a'.

Inlined Functions

Using the keyword 'inline' on a function definition (includes function body) inside a class declaration is redundant.

Friday, October 22, 2010

String Implicit Conversions

The C++ string type does not have an implicit conversion to 'const char *'.

Reference: Exceptional C++ by Herb Sutter. Addison-Wesley, 1999, p. 164.

Polymorphic Behavior

The following give you polymorphic behavior in C++:
   a. virtual functions
   b. templates
   c. overloading
   d. conversions

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 4.

Thursday, October 21, 2010

Traits Class

The following is a definition from the C++98 Standard:

"A traits class is a class that encapsulates a set of types and functions necessary for template classes and template functions to manipulate objects of types for which they are instantiated."

References:
   ISO/IEC International Standard 14882, Programming Languages — C++ http://www.open-std.org/jtc1/sc22/wg21/docs/projects#14882

More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 20.

Traits Class

Everything in a traits class is usually public.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 20.

Wednesday, October 20, 2010

Dependent Names

Dependent names only become visible at the point of instantiation.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 34.

Dependent Names

By default, dependent names are initially assumed by the compiler not to name a type.

This is why you sometimes need to use the 'typename' keyword to tell the compiler that something is a type. You cannot just use this keyword for every type using a template parameter. You can only use it for types that the compiler cannot figure out. Also, instead of peppering your code with 'typename', it is recommended that you use typedefs with the 'typename' keyword to simplify the code.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 33.

Tuesday, October 19, 2010

Dependent Name

The two ways that a dependent name will be treated as a type by the compiler are:
   1. Name lookup finds a type.
   2. The keyword 'typename' qualifies the type.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 33.

Typename

The following code does not compile:

    template<typename T>
    void func()
    {
        T::A a;
    }

The compiler does not know if T::A is a type. It could be several other things, which will only be known when the template is instantiated. You need the 'typename' qualifier here.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 33.

Monday, October 18, 2010

Typename

The following compiles:

template<typename T>
    void func()
    {
        typename T::A a;
    }

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 33.

Swap Trick

Assuming that you don't care about the cost of reallocations, the swap trick a good way to empty a container.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 52.

Sunday, October 17, 2010

Iterators

Assume that i is an iterator to a container.
 Are the following two lines functionally equivalent?
   func(i++);
   func(i); ++i;
An example would be if func was the erase function on a container. In the first case the iterator would still be valid after the function call. In the second case, the iterator would be invalid after the function call. Care in not invalidating the iterator is needed when erasing items from a container. Expressions like func(i++) are part of the idiom to erase items correctly. Here is an example: myMap.erase(i++) does not invalidate the iterator, i. Doing myMap.erase(i) in a loop is popular source of program crashes.

Reference: More Exceptional C++: 40 New Engineering Puzzles, Programming Problems, and Solutions by Herb Sutter. Addison-Wesley, 2001, p. 59.

Function Templates

You can't partially specialize a function template. You can only partially specialize a class template.

A class template is a template; a template class is an instantiation of a class template. A function template is a template; a template function is an instantiation of a function template.

References:
  More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 66.
  http://womble.decadentplace.org.uk/c++/template-faq.html#phrase-order

Function Guarantee

If i is an int, and f() is a function taking an int, if f(i++) is called and f() throws an exception, i guaranteed to be incremented.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 62.

Saturday, October 16, 2010

Inlined Functions

One of the negatives of inline functions is that when they change, clients need to recompile instead of just relinking.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 84.

Friday, October 15, 2010

Inlined Functions

One of the negatives of inlining large functions is that cache misses may increase.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2001, p. 84.

Inlined Template Functions

Non-exported templated functions are usually inlined.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002, p. 85.

Dietmar Kuhl (personal communication) pointed out, many class templates in the C++ Standard library are explicitly instantiated, thereby explicitly instantiating their member functions. Their member functions need not be inlined.

Thursday, October 14, 2010

Copy Constructors

The following is a declaration of a copy constructor:
   A(const A& a, int i = 0);

If you also declare A(const A& a), you will get a compiler error.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002, p. 107.

Wednesday, October 13, 2010

Default Objects

When functions are not defined in the class declaration, default arguments are specified in the function declaration; and not in the definition. The default objects are constructed in the definition.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002, p. 137.

auto_ptr

No auto_ptr operation can throw an exception.

This property of auto_ptr and of the swap() function is useful for writing exception-safe code.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 145.

Function Try Block

Given the following code:

    MyClass::MyClass()
    try
    : mSubobject(0)
    {
    }
    catch (...)
    {
    }


If mSubobject throws an exception during construction the MyClass constructor will rethrow the exception that mSubject threw.

This is a function try block. When something in the member initialization list throws an exception, the catch block can either rethrow the same exception, throw a different exception, or do nothing; in which case the runtime will rethrow the original exception. You can't suppress the exception.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 120.

Tuesday, October 12, 2010

Managed Resource Acquisition

mSubobject(new Component) is to 'Unmanaged Resource Acquisition' as auto_ptr(new Component) is to 'Managed Resource Acquisition'.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 123.

Class with an auto_ptr as a Member

If you have a class with an auto_ptr as a member, you must define or declare your own constructor, and copy constructor for your class.

This is needed to ensure a copy does what you want, otherwise when you make a copy of an object of this type, the destination auto_ptr member will take ownership from the source object. The compiler won't complain, but most likely your class won't do what you expect. If you define a copy constructor, the compiler will not provide a default construct. You will have to provide your own.


Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., pp. 148, 185.

Monday, October 11, 2010

Protocol Classes

Protocol classes (aka Interface Classes) contain only pure virtual functions and no data members.

You can add data members, and the compiler will not complain, but this will not be a typical protocol class.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 158.

Calling a Virtual Function in A Base Constructor or Destructor

You should never call a virtual function in a base constructor or destructor.

If your compiler is nice, it will generate code that will tell you this. Otherwise, I maybe hard to debug. Indirect calls to virtual functions add another layer of difficulty to debugging.

References:
   More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 170.
   http://www.artima.com/cppsource/pure_virtual.html

Sunday, October 10, 2010

Using auto_ptr with Arrays

The following code does not behave nicely:

    {
      auto_ptr<int> pArrayOfInt(new int[10]);
    }

The auto_ptr will do a delete instead of an array delete at the end of its lifetime.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 176.

Addresses of Zero Element Arrays

Given the following code:

      int *pInt1 = new int[0];
      int *pInt2 = new int[0];
      int *pInt3 = new int[0];

The following expression is true:

      ((pInt1 != pInt2) &&
       (pInt2 != pInt3) &&
       (pInt3 != pInt1)   )

This is described by the C++ standard.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 177.

Saturday, October 9, 2010

Template Parameters

The following cannot be used as a template parameter:
    local class
    unnamed class
    any class compounded from local or unnamed classes.

References:
  More Exceptional C++: 40 New Engineering Puzzles, Programming Problems, and Solutions by Herb Sutter. Addison-Wesley, 2002., p. 208.
  [C++98] section 14.3.1/2

Defining Functions inside Functions

You cannot define a function inside another function.

A famous error is when someone tries to construct an object with no constructor arguments, but leaves the parentheses in the expression. The compiler complains that you are trying to declare a function within a function.
  Examples:

     X x(1,2); // okay
     X x(1);   // okay
     X x();    // not okay
     X x;      // okay

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 209.

Friday, October 8, 2010

Copy Initialization vs. Direct Initialization

MyClass x; MyClass y(x); is direct initialization.
MyClass x; MyClass y = x; is copy initialization.
Copy Initialization ('=x') creates a temporary, where as Direct Initialization (y(x)) doesn't. Compilers can optimize out this temporary. The Sun CC compiler optimizes out the temporary. Thanks to Srinivas Shilangani for pointing this out. The naming looks like the opposite of that expected, since direct initialization is using the copy constructor. Copy initialization also uses the copy constructor, but it is not explicit.

References: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 224. And http://www.gotw.ca/gotw/036.htm


References: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 224. And http://www.gotw.ca/gotw/036.htm

Preferred Method of Initializing

The preferred method of initializing is:
   MyClass x; MyClass y(x);
instead of:
   MyClass x; MyClass y = x;
This is in case the compiler does not optimize out the temporary when using 'y = x'.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., pp. 224-225.

Thursday, October 7, 2010

Adding to the std Namespace

A program can't add anything to the std namespace. Although, you can argue that a template specialization is an addition.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002., p. 227.

Using-declarations

A using-declaration only brings in declarations that have already been seen.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002, p. 232.

Using-Directives

A using-directives brings in declarations even if they haven't been already seen.

Reference: More Exceptional C++: 40 New Engineering Puzzles, Programming Problems, and Solutions by Herb Sutter. Addison-Wesley, 2002, p. 233.

Wednesday, October 6, 2010

Using-declarations and Using-Directives

All using-declarations and using-directives should be after all #include statements.

Reference: More Exceptional C++ by Herb Sutter. Addison-Wesley, 2002, p. 237.

Tuesday, October 5, 2010

Template Typedef

The following code does not compile:
template <class T> 
typedef std::vector<T> MyVector;

The next version of C++ might allow it.

Reference: http://www.gotw.ca/gotw/079.htm

String Initialization

All of the following lines compile:

  string myString1 = "Hello";
  string myString2; myString2 = "Hello";
  string myString3 = string("Hello");

Monday, October 4, 2010

Template Declarations

When declaring a template, given that the definition begins with 'template <', the following keywords can follow: class, typename or template.

'template' would be used for template template parameters.

Double const Allowed in Template

The following compiles:

       template <typename T>
       class ConstType {
        public:
          typedef const T MyConst;
       };
       ConstType<const int>::MyConst i = 0;

Note the double const, and the compiler does not complain about it.

Reference: Modern C++ Design by Andrei Alexandrescu. Addison-Wesley, 2001, p. 37.

Using sizeof to Find Type Information at Compile-Time

sizeof allows you to find type information at compile time.

Reference: Modern C++ Design by Andrei Alexandrescu. Addison-Wesley, 2001, p. 34.

See the above reference for fancy examples.

Sunday, October 3, 2010

std::type_info

std::type_info allows you to find type information at run-time, not compile time.

Reference: Modern C++ Design by Andrei Alexandrescu. Addison-Wesley, 2001, p. 37.

Saturday, October 2, 2010

The typeid() Function

The Standard C++ Library function typeid() maps a class name to a string. The mapping is not standardized. Typically, the output is the class name as a string; but it could be "" and still be compliant.

Reference: Modern C++ Design by Andrei Alexandrescu. Addison-Wesley, 2001, p. 39.

References to Pointers

Function formal parameters may be of type 'reference to a pointer', but not of type 'pointer to a reference'.

Friday, October 1, 2010

Pass by Pointer vs. Pass by Reference

Even though you can pass an object by reference as a reference, if you want to change the object in a function; there is a convention of making the parameter a pointer to the object instead of a reference to the object to emphasize the fact that the object is an output parameter.

This is only a convention that some people use. The nice thing about this convention is that an output parameter is made obvious in the caller and the callee. You can argue that lack of 'const' may tell you it is an output parameter from the callee side, but: 1) it won't be shown on the caller side; and 2) parameters passed by value typically do not use the 'const' specifier.

References to References

You can't have a reference to a reference.

Reference: Modern C++ Design by Andrei Alexandrescu. Addison-Wesley, 2001, p. 43.