Effective C++

Some code snippets to test the items of Meyers book: Effective C++


Item 2: Prefer consts, enums, and inlines to #defines

At a first look, looking at the following code snippets, it could seem that the C++ way of using constants and macro is more complex that the c counterpart. Actually, when the code start to grow and the system to be debugged is bigger, type checking and the fact of having a different symbol for each of this elements is a big advantage.

Defines

C style

#define TEST 5
#define HELLO "Hello World"

C++ style

class Example
{
public:
    static const int Test = 5;
    static const std::string Hello;
    enum Number {one = 1, two = 2, three = 3};
    ...
};
const std::string Example::Hello = "Hello World";
...
std::cout << Example::Test  << std::endl; // 5
std::cout << Example::Hello << std::endl; // Hello World
std::cout << Example::one   << std::endl; // 1

Macro

C style

#define CALL_WITH_MAX(a, b)    F((a) > (b) ? (a) : (b))
#define F(arg)                 printf("arg = %d\n", arg)

C++ style

namespace test
{
    template<typename T> inline void callWithMax(const T& a, const T& b) 
    {                                               
        f(a > b ? a : b);
    }
 
    inline void f(int arg) 
    {
        std::cout << "arg = " << arg << std::endl;
    }
}
 
test::callWithMax(5, 6); // arg = 6

Item 3: Use const whenever possible

The wonderful thing about const is that it allows you to specify a semantic constraint a particular object should not be modified and compilers will enforce that constraint. It allows you to communicate to both compilers and other programmers that a value should remain invariant. Whenever that is true, you should be sure to say so, because that way you enlist your compilers' aid in making sure the constraint isn't violated.

Things to Remember

  • Declaring something const helps compilers detect usage errors. const can be applied to objects at any scope, to function parameters and return types, and to member functions as a whole.

   char greeting_1[] = "Hello";
   char greeting_2[] = "world";
 
   // NON-CONST POINTER, NON-CONST DATA:
   char *p_1 = greeting_1;
   cout << p_1 << endl; // Hello
 
   // change pointed value:
   p_1 = greeting_2;
   cout << p_1 << endl; // world
 
   // change data:
   p_1[0] = 'W';
   cout << p_1        << endl; // World
   cout << greeting_2 << endl; // World
 
   // NON-CONST POINTER, CONST DATA:
   const char *p_2 = greeting_1; // Equivalent: char const *p_2 = greeting_1;
   cout << p_2 << endl; // Hello
 
   // change pointed value:
   p_2 = greeting_2;
   cout << p_1 << endl; // World
 
   // change data:
   // p_2[0] = 'w';      <-- COMPILER ERROR: assignment of read-only location
 
   // CONST POINTER, CONST DATA:   
   char const * const p_3 = greeting_1; // Equivalent: char const * const p_3 = greeting_1;
   cout << p_3 << endl; // Hello
 
   // change pointed value:
   // p_3 = greeting_2;  <-- COMPILER ERROR: read-only variable 'p_3'
 
   // change data:
   // p_3[0] = 'w';      <-- COMPILER ERROR: assignment of read-only location

Const iterator: don't allows the modification of the container elements

IntVector vector;
IntVector::const_iterator i;
vector.push_back(1);
vector.push_back(2);
vector.push_back(3);
for (i = vector.begin(); i != vector.end(); i++) {
    // (*i) = 1;   <-- COMPILER ERROR: assignment of read-only location
    std::cout << "(*i)" << (*i) << std::endl;
}

Operators overloading: if const were not used it would be possible to assign a new result to a return variable. Only the const keyword in the return variable of the operator gives a compilation error for the following expression

(dummyA * dummyB) = dummyC;

cpp/effective_cpp.txt · Last modified: 2010/08/10 (external edit)
CC Attribution-Noncommercial-Share Alike 3.0 Unported
Valid CSS Driven by DokuWiki Recent changes RSS feed Valid XHTML 1.0