JonHoyle.com Mirror of MacCompanion
http://www.maccompanion.com/macc/archives/December2009/Columns/AccordingtoHoyle.htm

macCompanion
macCompanion magazine

macCompanion

Blog

Archives

Products

Services

About Us

FAQs

Resources

 

Consultants

Developers

Devotees

Downloads

"Foreign" Macs

Forums

Hearsay

Link Lists

Mac 3D

Macazines

Mac Jobs

MUG Shots

News

Radio

Reviews

Think Different

Training

 

Download this issue

According to Hoyle

According to Hoyle...

C++0x Part 3: Making Coding Easier

 

macCompanion

December 2009

by Jonathan Hoyle

jonhoyle@mac.com

http://www.jonhoyle.com

 

Two months ago, we began our series on the changes that will be coming the C++ language.  Last month we examined some of the updates which were expected to take place: fixing embarrassments and syncing up with ANSI C99 changes.  With this month, we look at some more improvements available to C++ developers of the future.  Specifically, changes which make coding easier.

 

 

Standard C++ Library Enhancements


The Standard C++ Library, including STL (the Standard Template Library), is a generous supply of useful containers and utilities. Despite its fullness of capabilities, there were still a number of components missing.  C++0x fills these gaps:

    
regexA long awaited regular expressions class

    array<>: A one-dimensional array containing its size (can be 0)

    STL hash classes: unordered_set<>, unordered_map<>, etc.

    tuple<>: A templated tuple class, eg: tuple<int,void *,double>


Mac users are fortunate in that they do not have to wait for the Standard Library changes: they are available today in gcc 4 (the compiler inside Xcode 2.x and later).  These library additions are within the library namespace std::tr1:: ("tr1" stands for Technical Report #1, the standard's committee report defining these new classes).

 

 

 

Variadic Templates


For years, the C language has allowed functions to have a variable number of parameters.  Unfortunately, this was not true of template arguments within C++98.  In C++0x, templates can have a variable number of types.  Here is an example in which a templated DebugMessage() function can take advantage of variadic templates:

    // Prints to stderr only when DEBUG flag set
    template <typename... TypeArgs>
    void DebugMessage(TypeArgs... args)

    {

        #ifdef DEBUG
            
... // Implement writing to stderr

        #else
            
    // Do nothing

        #endif

    }


    // Later in code
    
DebugMessage("The value of n = ", n)

    DebugMessage("x = ", x, ", y = ", y, ", z = ", z)

    DebugMessage("TRACE:",

                                  " time = ", clock(),

                                  ", filename = "__FILE__,

                                  ", line number = "LINE__,

                                  ", inside function = ", __func__);


This new flexibility with macros will make it easier for developers wishing to use them, as their current restrictions make them occasionally cumbersome.

 

 

 

Delegating Constructors


Other languages, such as C#, allow one class constructor to invoke another.  In C++98, this was not possible, thus requiring the class designer to create a separate initialization function if it wished to use common code across multiple constructors.  In C++0x, this becomes available, as the following example shows:

    class X
    {
        public:
            X();           // default constructor
            X(void *ptr);  // takes a pointer
            X(int value);  // takes an int
    };

    X::X(): X(NULL// calls X(void *)
    {
        ...  // other code
    }

    X::X(void *ptr): X(0// calls X(int)
    {
        ...  // other code
    }

    X::X(int value) // does not delegate
    {
        ...  // other code
    }


With constructor delegation, C++ class designers can simplify their implementations.

 

 

 

NULL Pointers


In ANSI C, NULL is defined as (void *) 0.  In C++, the use of NULL is deprecated.  Why?  Because unlike in C, it is illegal in C++ to directly assign a void pointer to any other type of pointer (without a cast):

    void  *vPtr = NULL;   // legal C, legal C++
   
int   *iPtr = NULL;   // legal C, illegal C++
                          // Cannot assign void * to int * in C++
    int   *iPtr = 0;      // legal C++


However, the proliferation of NULL in C++ code remains so great, many compilers simply generate a warning, not an error, when such a pointer assignment mismatch takes place.  Others redefine NULL in C++ as simply 0.  Despite these occasional compiler courtesies, it is still very confusing for beginning C++ programmers, especially in examples such as these:

    void foo(int);       // takes an int
    
void foo(char *);    // takes a char ptr
 
    foo(0);              // Is this "0" to be a ptr or a number?
    foo(NULL);           // No matching prototype (no void *)


For this reason, C++0x introduces nullptr, a type-safe nil pointer which can be used with any pointer, but is not compatible with any integral type:


    char *cPtr1 = nullptr;    // a null C++ pointer
    char *cPtr2 = 0;          // legal, but deprecated
    int nnullptr;          // illegal
    X *xPtrnullptr;        // can be used with any ptr type
 
    void foo(int);            // takes an int
    
void foo(char *);         // takes a char ptr
 
    foo(0);                   // calls foo(int)
    foo(nullptr);             // calls foo(char *)


Essentially, C++ programmers now have a type-safe replacement for NULL, which matches similar behavior in other more recent languages.

 

 

 

The Amazing Return of auto


When the C language first evolved, the auto keyword was used to specify to the compiler that a variable was being allocated on the stack, for example:

    auto     x;     /* implicitly an int, placed on stack */

Then ANSI C was ratified in 1989, the implicit int rule was removed:

    auto     x;     /* now illegal in ANSI C */
    int      x;     /* OK, auto assumed */
    auto int x;     /* OK, but redundant */

Since that time, auto remained a keyword in the C (and later C++) languages, even though virtually no one had used it since the 1970's.  After over 30 years of disuse, the C++0x standard will reintroduce the auto keyword to mean that the variable type is implied by the initializer:

    auto       x = 10;     // x is an int
    auto       y = 10.0;   // y is an double
    auto       z = 10LL;   // z is a long long
    const auto *p = &y;    // p is a const double *

The savings becomes more significant with complicated types, such as the following example:

    void *foo(const int doubleArray[64][16]);

    auto       myFcnPtr = foo;
               // myFcnPtr is of type "void *(const int(*)[16])"

In addition, auto becomes useful for temporary variables whose types aren't important but merely just have to match.  Consider the following function which walks through an STL container:

 

         void foo(vector<MySpace::MyClass *> x)

         {

            for (auto ptr = x.begin(); ptr != x.end(); ptr++)

            {

               ...  // Code modifying the data

            }

         }

 

Without auto, the type for variable ptr would be  vector<MySpace::MyClass *>::iterator.  Moreover, any change to this container, such as changing it from a vector<> to a list<>, or changing the class name or namespace, would require changes in the ptr variable definition, despite the fact its type is completely unnecessary to note (other than for the compiler).

 

Note that an initializer is still required to use auto for C++0x:

 

         auto   x; // still illegal in C++0x

 

But suppose you knew what type you wanted (based upon another variable) but did not want to initialize?  The new decltype keyword is available for just such purposes, as the following example shows:

 

         bool SelectionSort(double data[256], double tolerance);

         bool BubbleSort(double data[256], double tolerance);

         bool QuikSort(double data[256], double tolerance);

         decltype(SelectionSort)  mySortFcn;

         if (bUseSelectionSort)   mySortFcn = SelectionSort;

         else if (bUseBubbleSort) mySortFcn = BubbleSort;

         else                     mySortFcn = QuikSort;

 

With the inclusion of auto & decltype in C++0x, a great deal of simplicity is restored to C++ development, without any loss of power. 

 

Coming Up: 

C++0x Part 4: Smart Pointers

C++0x Part 5: Rvalue References

C++0x Part 6: Final Thoughts

 

To see a list of all the According to Hoyle columns, visit:  http://www.jonhoyle.com/maccompanion 

 

http://www.maccompanion.com/macc/archives/December2009/Columns/AccordingtoHoyle.htm