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

Google

macCompanion

Internet

Header

Alternative Energy User Group

 


 

Bodelin Technologies - Home of the Proscope USB Digital Microscope

Bodelin Technologies - Home of the Proscope USB Digital Microscope

 

PowerMax: Sasquatch Approved!

Used Macs & Apple Computers

The Mac Store - Apple Computers in Oregon & Washington

The Mac Store - Apple Computers in Oregon & Washington

 

IrisInk - Portland & Seattle IT Consultants

IrisInk - Portland & Seattle IT Consultants

 

 


Latest Joy of Tech!
Today's Joy of Tech!


Visit StepHouse Networks. Broadband DSL for Apple Users



Legacy Links

 

Consultants

Developers

Devotees

Forums

Jobs and Careers

Mac 3D

Macazines

News

Think Different

 

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 to the C++ languageLast 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 many of these gaps:


    regex: A 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 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.


Visit here for more on Variadic Templates.




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.


Visit here for more on Delegating Constructors.




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 (that is, not 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, this 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 type, but is not compatible with any integral type:


    char *cPtr1 = nullptr;    // a null C++ pointer
    char *cPtr2 = 0;          // legal, but deprecated
    int n = nullptr;          // illegal
    X *xPtr = nullptr;        // 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(NULL);                // calls foo(char *)


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


Visit here for more on nullptr.




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 the stack */

Then ANSI C was ratified in 1989, and 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, due to its being completely redudndant.  Now after over 30 years of disuse, the C++0x standard reintroduces the auto keyword to mean that the variable's type is implied by its initializer, as so:


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

The savings becomes even more significant with complicated types, such as in 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(const vector<MySpace::MyClass> &x)
    {
        for (auto ptr = x.begin(); ptr != x.end(); ptr++)
        {
            ...  // code accessing the data
        }
    }

Without auto, the type for variable ptr that would have to be put in this for-loop would be:


    const vector<MySpace::MyClass>::const_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 in 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 it just yet?  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) mySortingFunction;

    if (bUseSelectionSort)
        mySortingFunction = SelectionSort;
    else if (bUseBubbleSort)
        mySortingFunction = BubbleSort;
    else
        mySortingFunction = QuikSort;

    // Now sort my data
    mySortingFunction(dataToSort);


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


Visit here for more on the auto keyword.




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