Thursday, September 30, 2010

Early Optimization

The quote "Early optimization is the root of all evil." was said by C.A.R. (Tony) Hoare, but is often attributed to Donald Knuth.

Reference: http://en.wikipedia.org/wiki/Optimization_(computer_science)


The following is a list of some typical 
(but not necessarily bad) pre-optimizations:
   1) Denormalizing Database Tables 
      (i.e. duplicating data)
   2) Exposing implementation detail
   3) Caching (i.e. duplicating data)
   4) Avoiding in-memory copies 
      (Usually has no performance impact)
   5) Copy on Writes (COW); 
      Penalties for Multithhreading even for 
      single threading 
      (See More Exceptional C++)
   6) Skipping Interface Design 
      (Usually causing implementation detail
      leaks and unnecessary dependencies)
   7) Putting multiple purposes in a 
      function/class.
   8) Inlining (Increasing dependencies)
   9) Inlining assembly 
      (Usually has no performance impact)
  10) Using arrays instead of vectors.
  11) Using char* instead of string
  12) Increasing coupling
  13) Decreasing cohesion
  14) Unrolling loops
  15) Macro usage to inline code, or build tables.

Pass by Value

Fundamental types are best passed to a function by value instead of reference.

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

Wednesday, September 29, 2010

Template Specialization

'Template specialization' is to 'compile-time if' as 'virtual function' is to 'run-time if'.

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

Many times when you see switching on types, it indicates a non-object-oriented design. Some of the places where it is usually okay are:

1) when unmarshalling data from across a wire; and

2) when implementing a virtual constructor

Tuesday, September 28, 2010

Compile-time Calculations via Templates

Compile-time calculations via templates use recursion instead of iteration, because compile-time values are immutable. New names are used instead of the same names having their values changed.

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

Many times an enum value is calculated via a previous enum value. It can be shown that this "generic meta-programming" is Turing Complete, which means in theory, it can basically compute what a typical computer could compute. In reality, the recursion is limited to a certain number of times.

Monday, September 27, 2010

Macros

Macros in C++ cannot be recursive.

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

Sunday, September 26, 2010

Order of Destruction of Objects in Standard Containers

The C++ Standard does not define the order of destruction of objects in standard containers.

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

Saturday, September 25, 2010

Reference Counting Smart Pointers

The Standard C++ Library does not define a reference counting smart pointer. They are in the free Boost C++ Library, and will be in C++0x.

Friday, September 24, 2010

Hash Containers

The Standard C++ Library does not define hash containers. They are in the Boost C++ Library; and will be in C++0x, the next version of the C++ standard.

See:

http://en.wikipedia.org/wiki/C%2B%2B0x
http://www2.research.att.com/~bs/C++0xFAQ.html

http://en.wikipedia.org/wiki/Boost_C%2B%2B_Libraries
http://www.boost.org/

Thursday, September 23, 2010

Double-check Locking Pattern

The 'Double-check Locking Pattern' is used for getting instances of a singleton without always having to go through a guard.

First you check the pointer to the singleton object, then enter the guard's scope, then check the pointer again. Once the pointer is set, you no longer use the guard.

Reference: Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu. Addison-Wesley, 2001, pp. 146-147.

Wednesday, September 22, 2010

Phoenix Singleton

A Phoenix Singleton is a singleton that can be recreated after it is destroyed.

An example where this might be useful is in a logger that might be destroyed on shutdown, but then another error occurs that you want to log; so you bring back the logger singleton.

Reference: Modern C++ Design by Andrei Alexandrescu. Addison-Wesley, 2001, pp. 137-138.

Tuesday, September 21, 2010

References to Functions

You can have references to regular functions, but not member functions.

Reference: Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu. Addison-Wesley, 2001, p. 117.

Monday, September 20, 2010

Static Functions

Static functions cannot be virtual.

Reference: Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu, Andrei. Addison-Wesley, 2001., p. 130.

Sunday, September 19, 2010

Singleton References

Returning a reference to a singleton is safer, because it prevents users from deleting it.

Reference: Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu. Addison-Wesley, 2001, p. 132.

Saturday, September 18, 2010

Singleton Destructors

Singleton destructors should be private.

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

Friday, September 17, 2010

Volatile Member Functions

Just as you cannot call a const object's non-const member functions, you cannot call a volatile object's non-volatile member functions.

Here is a code example:

#include 
using namespace std;

class A
{
 public:
   void volatile_func() volatile
   {
      cout << "    volatile_func" << endl;
   }
   void non_volatile_func()
   {
      cout << "non_volatile_func" << endl;
   }
   void const_func() const
   {
      cout << "       const_func" << endl;
   }
   void non_const_func()
   {
      cout<< "   non_const_func" << endl;
   }
};

int main()
{
   volatile A aVolatile;
            A aNonVolatile;
   const    A aConst      = A();
            A aNonConst;
   aVolatile.volatile_func();
   ///////////////////////////////////////
   // The following line does not compile.
   //    aVolatile.non_volatile_func();
   ///////////////////////////////////////
   aNonVolatile.volatile_func();
   aNonVolatile.non_volatile_func();

   aConst.const_func();
   ///////////////////////////////////////
   // The following line does not compile.
   //    aConst.non_const_func();
   ///////////////////////////////////////
   aNonConst.const_func();
   aNonConst.non_const_func();
   return 0;
}

Thursday, September 16, 2010

Pointers to Volatile

You cannot assign a 'pointer to volatile' to a 'pointer to non-volatile', but you can assign a 'pointer to non-volatile' to a 'pointer to volatile'.

This is similar to the rules for 'pointer to const' and 'pointer to non-const'.

You cannot assign a 'pointer to const' to a 'pointer to non-const', but you can assign a 'pointer to non-const' to a 'pointer to const'.

It is like 'pointer to volatile' and 'pointer to const' have special powers during assignment.

To force the assignment for either one, you would need to use const_cast<>() to cast away the volatile or const.

Here is a code example:

#include 
#include 
using namespace std;

int main() {
   volatile int    i_volatile = 3;
            int    i          = 5;
   const    int    i_const    = 7;
   volatile int * pi_volatile = &i_volatile;
            int * pi          = &i;
   const    int * pi_const    = &i_const;

   i = i_volatile;
   i_volatile = i;

   ///////////////////////////////////////////
   // The following line does not compile:
   //   pi     = pi_volatile;
   ///////////////////////////////////////////
   pi_volatile = pi;

   ///////////////////////////////////////////
   // The following line does not compile:
   //   pi  = pi_const;
   ///////////////////////////////////////////
   pi_const = pi;

   return 0;
}

Wednesday, September 15, 2010

Initializing a Static Variable at Compile Time

For a static variable to be initialized at compile time, it needs to be initialized by a compile-time constant, and cannot have a constructor; Otherwise, it is initialized at runtime.

Reference: Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu. Addison-Wesley, 2001, p. 133-134.

Tuesday, September 14, 2010

realloc()

realloc() provides all of the functionality of malloc() and free().

Reference: Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu. Addison-Wesley, 2001, p. 143.

Monday, September 13, 2010

Throwing Exceptions

The following statements compile:
        throw 99;
        throw "Hello";
You can throw any object that can be copied.

Sunday, September 12, 2010

Calling delete on a pointer to const

You can call delete on a pointer to const.

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

Saturday, September 11, 2010

Declaration in if Statement

The following code compiles.

if (int i = 1) {}

This is sometimes used to allocate a resource that is used within the scope of the if statement.

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

Here is some example code:
// File: decl_in_if.cpp
#include 
using namespace std;

int main() {
    if (int i = 0)
    {
        i = 11;
        cout << "Test 1 failed" << endl;
    }
    else
    {
        i = 23;
        cout << "Test 1 passed" << endl;
    }
    if (int j = 1)
    {
        j = 29;
        cout << "Test 2 passed" << endl;
    }
    else
    {
        j = 31;
        cout << "Test 2 failed" << endl;
    }
    return 0;
}
/* The above program prints out the following:
 *
 * Test 1 passed
 * Test 2 passed
 *
 */

Friday, September 10, 2010

Volatile

If you share a variable with multiple threads, you should specify that variable as volatile.

Reference: Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu. Addison-Wesley, 2001. p. 308.

Thursday, September 9, 2010

Repeated Enum Values

You can repeat values in an enum. For example:
enum RGB
{
   StartValue,
   Red       = StartValue,
   Green     , 
   StopValue ,
   Blue      = StopValue,
   RgbCount
};

Wednesday, September 8, 2010

const_cast<>() and the volatile type qualifier

You can use const_cast<>() to remove the volatile qualifier.

Reference: The C++ Standard Library: A Tutorial and Reference by Nicolai M. Josuttis. Addison-Wesley, 1999, p. 20.

I tried this on a couple of compilers.

It worked on the IBM AIX compiler, but it did not work on the Sun compiler.

It only worked for references, pointers and pointers to data members.

See also: volatile - Multithreaded Programmer's Best Friend by Andrei Alexandrescu.

Tuesday, September 7, 2010

Comma Operator

After the following statement:
    int i = (10, 5);
The value of i is 5.

The comma operator is being used above, so the last value, 5, is the value of the expression (10, 5).

Reference: The C++ Standard Library by Nicolai M. Josuttis. Addison-Wesley, 1999, p. 20.

Monday, September 6, 2010

Exceptions

The following Exception Classes are related as follows:
A logic_error is a domain_error. A runtime_error is a range_error.

Reference: The C++ Standard Library by Nicolai M. Josuttis. Addison-Wesley, 1999, p. 26.

A way to remember this:
It is a logic_error for providing bad input (domain) to an object.
During an object's runtime, something might go out of range.
(It's just a mnemonic)

Sunday, September 5, 2010

Exception Specifications

A function's exception specification of throw() indicates the function does not throw exceptions. If the function does throw an exception, the program will terminate unless some extra measures are taken. Exception specifications have fallen out of favor because of this; although the Standard C++ Library sometimes uses them to indicate their exception guarantees.

Saturday, September 4, 2010

Exceptions

The following include files declare the Standard C++ Library's exceptions: <exception>, <new>, <typeinfo>, <ios>, and <stdexcept>.

Reference: The C++ Standard Library by Nicolai M. Josuttis. Addison-Wesley, 1999, p. 28.

Friday, September 3, 2010

std::exception

throw std::exception("my bad"); does not compile, but throw std::out_of_range("too big"); does.

std::exception can be derived from, but cannot be thrown directly. It is the base class for all of the C++ Standard Library exceptions. Here is the exception hierarchy:
exception
        bad_alloc
        bad_cast
        bad_exception
        bad_typeid
        io_base::failure
        logic_error
            domain_error
            invalid_argument
            length_error
            out_of_range
        runtime_error
            overflow_error
            range_error
            underflow_error
Reference: The C++ Standard Library by Nicolai M. Josuttis. Addison-Wesley, 1999, p. 30.

Thursday, September 2, 2010

Local Object Destructors

When you call exit(), the destructors of local objects do not get called before the program ends.

Wednesday, September 1, 2010

auto_ptr

It is not okay to pass auto_ptrs as references.

Reference: The C++ Standard Library: A Tutorial and Reference by Nicolai M. Josuttis. Addison-Wesley, 1999, p. 43.

See also the following link for some reasons why:
http://nicoletti.50megs.com/cpp_notes/auto_ptr/pass.html