Click here to Skip to main content
Click here to Skip to main content

C++11 – A Glance [part 1 of n]

, 2 Feb 2012
Rate this:
Please Sign up or sign in to vote.
A glance at the C++11 Standard, covering features supported in VS2010.

Introduction

C++0x is now a formal standard and will hereafter be called as C++11. It is ratified by ISO C++ in the year 2011.
The purpose of this article is to give a bird's eye of most of the C++11 features and for those features which are already shipped into VS2010 a deep analysis is given. This article can serve as a platform to start comprehensive study on individual features.

The article is divided into parts so that the length is at bay. I myself will get scared to read a lengthy stuff. Moreover it will be boring to grab every thing in one sitting.

As this is my first article in codeproject, please bear with the formatting and with the typos if any.

Background

It took almost a century for Charles Babbage's Difference Engine to evolve into a electrically powered computer. In the 1940s, only assembly level languages are used owing to the then computer's low speed and memory capacity. Things started to turn after a decade and the period between 1950 to 1970 saw blooming of many programming languages of which many survived till date.
In 1979 Bjarne Stroustrup working for the Bell labs began enhancing the "C" language first adding classes, then virtual functions, operator overloading, multiple inheritance, templates, and exception handling among other features. He called it initially "C with Classes". It was renamed to C++ [++ may be to say that it increments C] in the year 1983.

C++ Landmarks/Iterations time line:

1983 - First commercial C++ compiler
1998 - C++ standards committee standardized C++ [C++98]
2003 - A bug patch with no new features [C++03]
2005 - A technical report called “Library Technical Report” (TR1 for short) was released
2011 - Introduced significant number of features and also enhanced C++ standard library.

As we can see that this iteration is the biggest one ( ok..ok...STL addition may also be big).

Do we have to know this new Standard ??

YES .The sooner the better. Resisting change is human. But we programmers/developers will be out of job the day when every language or project reaches static phase. We like to be in dynamic projects and the same is with language.
Change is inevitable and when an expert committee brainstormed for almost a decade then the result will obviously be beautiful and fruitful.

Even if we are not interested in incorporating these new iterations in the code, a quick glance on the features will help us to avoid or even think before coding certain scenarios using old compilers. Moreover by just switching to a compiler supporting C++11 we will be immensely benefited as the Standard template library is enhanced and revamped for performance. So if your project is using STL contianers/algorithms, then switch as early as possible.

C++11 Features

Here is a table summarizing core C++11 features and also their implementation status in VS2010

Feature

Intent

VS2010 status

  • auto
  • Usability improvement

    yes

  • decltype
  • Usability improvement

    yes

  • Trailing return types
  • Usability & Performance improvement

    yes

  • Right angle brackets
  • Usability improvement

    yes

  • static_assert
  • Usability improvement

    yes

  • nullptr
  • Usability & Performance improvement

    yes

  • Strongly typed enums
  • Type safety improvement

    partial

  • Rvalue references
  • Performance improvement

    yes

  • Move semantics
  • Performance improvement

    yes

  • long long
  • Performance improvement

    yes

  • Override control
  • Usability improvement

    yes

  • Lambda expressions
  • Usability & Performance improvement

    yes

  • preventing narrowing
  • Performance improvement

    no

  • Range based for-loops
  • Usability & Performance improvement

    no

    STL Enhancements

  • array
  • yes

  • Really smart pointers [unique_ptr, shared_ptr, weak_ptr]
  • yes

  • bind and function
  • yes

  • tuple
  • yes

  • unordered_map, unordered_set
  • yes

  • forward_list
  • yes

    ...... and many more

    Individual Features

    auto keyword:

    This feature is introduced in a effort to make C++ a more usable language. The committee have given a new meaning for the 'auto' keyword [just to remind the readers that the old auto keyword is used to declare a variable having local scope and all local variables if their storage class is not specified as static, extern or register are implicitly converted to auto storage-class specifier].

    As per the new interpretation, auto helps in deducing the type of the defined object by inspecting the RHS expression or it's initializer.

    auto i = 5    // i will be of type int
    
    int n=3;
    double pi=3.14;
    auto j=pi*n;    // j will be of type double
    

    Now let's take a case where the type is hard to write

     // take a hypothetical Map of ( int and an map(int,int) )
      map< int, map<int,int> > _Map;
      // see the verbose for defining a const iterator of this map
    map<int, map<int,int>>::const_iterator itr1 = _Map.begin();
     // now with auto our life gets simplified
    const auto itr2 = _Map.begin(); 

    Now take a case where the type is hard to know

    template<class U, class V>
    void Somefunction(U u, V v)
    { 
        ??? result = u*v; // now what would be the type of result ??? 
    
        // with auto we leave the compiler to determine the type
        auto result = u*v;
     }

    I will be extending this function for the next feature to know more usability of auto. The auto keyword finds more usage while declaring and initializing a variable to a lambda expression [we will cover lambdas soon].

    Few points on this feature:

    1. we can use const, volatile, pointer(*), reference (&), rvalue reference (&& - we will know about this shortly) specifiers on auto keyword

    auto k = 5;
    auto* pK = new auto(k);
    auto** ppK = new auto(&k);
    const auto n = 6; 

    2. A variable declared as auto must have an initializer.

    auto m; // m should be intialized  

    3. A auto keyword can not be joined with another type

    auto int p; // no way

    4. A method/template parameters cannot be declared as auto

    void MyFunction(auto parameter){} // no auto as method argument 
    
    template<auto T> // utter nonsense - not allowed
    void Fun(T t){}
    

    5. A variable that is declared on heap with the auto keyword using expression must have an initializer

      int* p = new auto(0); //fine
      int* pp = new auto(); // should be initialized 
      
      auto x = new auto(); // Hmmm ... no intializer
       
      auto* y = new auto(9); // Fine. Here y is a int*
      auto z = new auto(9); //Fine. Here z is a int* (It is not just an int)
    

    6. As auto keyword is a placeholder for a type, but is not a type itself, hence auto cannot
    be used for typecasting or operators such as sizeof and typeid.

    int value = 123;
    auto x2 = (auto)value; // no casting using auto
    
    auto x3 = static_cast<auto>(value); // same as above 

    7. All the variables in a declarator list that is declared with the auto keyword must resolve to
    the same type

      auto x1 = 5, x2 = 5.0, x3='r';  // This is too much....we cannot combine like this

    8. Auto does not deduce CV-qualifiers (constant & Volatile qualifiers) unless declared as
    a reference

        const int i = 99;
        auto j = i;       // j is int, rather than const int
        j = 100           // Fine. As j is not constant 
    
       // Now let us try to have reference
        auto& k = i;      // Now k is const int& 
        k = 100;          // Error. k is constant
    
       // Similarly with volatile qualifer

    9. auto decays arrays to pointers unless declared as a reference.

      
      int a[9];
      auto j = a;
      cout<<typeid(j).name()<<endl; // This will print int*
    
      auto& k = a;
      cout<<typeid(k).name()<<endl; // This will print int [9]
    
    

    decltype type specifier:

    return_value decltype( expression )
    [ return_value is the type of the expression parameter ]

    This can be used to determine the type of a expression. As hinted by Bjarne, if we just need the type for a variable that we are about to initialize auto is often a simpler choice. But if we need a type for something that is not a variable, such as a return type then decltype is the thing we should be trying.

    Now lets look back an example we worked earlier,

    template<class U, class V>
    void Somefunction(U u, V v)
    { 
       result = u*v; // now what would be the type of result ??? 
    
       decltype(u*v) result = u*v; // Hmm ....we got what we want
    }

    In the next section I will make you familiar with the notion of combining auto and decltype to declare template functions whose return value type depends on its template arguments.

    Few points on decltype:

    1. If the expression is a function, then decltype gives the type of the return of the function

    int add(int i, int j) { return i+j; }
    
    decltype( add(5,6) ) var = 5; // Here the type of var is return of add( ) -> which is int

    2. If the expression is an lvalue then decltype gives lvalue reference to the type of the expression.

    struct M { double x; };
    
    double pi = 3.14;
    const M* m = new M();
    decltype( (m->x) ) piRef = pi;
    
        // Note: Due to the inner bracets the inner statement is evaluated as expression,
        // rather than member 'x' and as type of x is double and as this is lvale
        // the return of declspec is double& and as 'm' is a const pointer 
        // the return is actually const double&.
        // So the type of piRef is const double&
    3. It is important to note that decltype does not evaluate the expression as auto
    does but just deduces the type of the expression
        int foo(){}
        decltype( foo() ) x; // x is an int and note that 
                             // foo() is not actually called at runtime

    Trailing return types:

    This is completely a new feature for C++ developers. Till now the return value of a function should go before the function's name. From C++11, we can also put the return type at the end of the function declaration, of course only after substituting auto for the name of the return type. Now why we want to do this. Let's find out:

    template<class U, class V>
    ??? Multiply(U u, V v)    // how to specifiy the type of the return value
    { 
       return u*v;
    }

    We can not obviously do like:

    template<class U, class V>
    decltype(u*v) Multiply(U u, V v)    // Because u & v are not defined before Multiply.
                         //  What to do...what to do !!!
    { 
       return u*v;
    }

    In this situation we can use auto and then latter once u&v's definitions are known we can specify the return type using decltype.
    Cool isn't it?

    template<class U, class V>
    auto Multiply(U u, V v) -> decltype(u*v)    // Note -> after the function bracet.
    { 
       return u*v;
    }

    Right angle brackets:

    Look at this declaration,

    map<int, vector<int>> _Map;

    This is an error with earlier compilers as there is no space between >'s and the compiler will treat it as right shift operator.
    But C++11 compilers will parse these multiple right angle brackets as closing to the template argument list and saves us from need of putting space between > .
    This is not a great feature when compared to the rest, but as we c++ developers look for perfection, here is the one that is taken care of.

    static_assert:

    This macro can be used to detect and diagnose compile-time errors. Compile-time period. This is in contrast to the CRT-assert macro which an assertion at run-time. This goody can be used to check program invariants at compile-time.

    This takes an expression that can be evaluated to bool and an string literal. If the expression evaluates to false, then the compiler issues an error containing the specified string literal and the compilation is failed. If true the declaration has no effect.

    We can use static_assert at

    A. namespace/global scope:

    static_assert(sizeof(void *) == 4, "Oops...64-bit code generation is not supported.");

    B. class scope:

    template<class T, int _n>
    
    class MyVec
    { 
        static_assert( _n > 0 , "How the hell the size of a vector be negative");
    };
    
    void main()
    {
        MyVec<int, -2> Vec_;
        // The above line will throw error as shown below ( in VS2010 compiler):
        //   > \main_2.cpp(120) : error C2338: How the hell the size of a vector be negative
        //   > main_2.cpp(126) : see reference to class template instantiation 'MyVec<t,_n />'
        //     being compiled
        //   > with
        //   > [ 
        //        > T=int, 
        //       > _n=-2
        //   > ]
    
        // This is fine
            MyVec<int, 100> Vec_;
    }

    C. block scope:

    template<typename T, int div>
    void Divide( )
    { 
       static_assert(div!=0, "Bad arguments.....leading to division by zero");
    } 
    
    void main()
    { 
       Divide<int,0> ();
       // The above line will generate
       // error C2338: Bad arguments.....leading to division by zero
    } 

    Do remember that since static_assert is evaluated at compile time, it cannot be used to check assumptions that depends on run-time values like the arguments of a function

    void Divide(int a, int b)
    { 
       static_assert(b==0, “Bad arguments.....leading to division by zero”);
       // sorry mate! the above check is not possible via static_assert...use some other means
    } 

    The static_assert declaration is especially useful for debugging templates. The compiler evaluates the constant-expression parameter immediately if it does not depend on a template parameter. Otherwise, the compiler evaluates the constant-expression parameter when the template is instantiated.

    nullptr:

    This feature is introduced mainly to take care of the pitfalls generated by using the (infamous and nasty) NULL macro. As we all know that NULL is nothing but a preprocessor expanding to 0 at compile time and this expansion often leads to ambiguity. Take for case,

     void SomeFunction(int i){ } 
    
     void SomeFunction(char* ch) { } 

    now a call like : SomeFunction(NULL) will always be resolved to SomeFunction(int i), even though we want to call SomeFunction(char* ch) with null pointer argument.
    To force we have to call like: SomeFunction( (char*) NULL ) // yak ..ugly
    To avoid these inconveniences the nullptr is introduced finally. The nullptr literally means null pointer is not an integer. This can thus be safely used to indicate that an object handle, interior pointer, or native pointer type does not point to an object.



    Some of the features are covered in the second part of this series. Please refer to "C++11 – A Glance [part 2 of n]".


    Rest of the features will be covered in the coming parts.


    Thank you for reading this article. It would be helpfull if you rate/send feedback, so that I can improve while working on the remaining parts or updating this part with new information.

    Other sources

    As the standard is freezed just 3 months ago, there are no books describing the new features. Here are few references which are useful to get a deep insight on all the features.

    http://www2.research.att.com/~bs/C++0xFAQ.html
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/

    Acknowledgments

    Thanks to Clement Emerson for his views and review.

    History

    January 09 2012 : Added Introduction and Part-1
    January 14 2012 : Added links to Part-2, "C++11 – A Glance [part 2 of n]".
    January 15 2012 : A typo corrected.
    January 21 2012 : Corrected few broken links [no additional information]
    January 25 2012 : Added few points to auto and decltype (as mentioned by user 'ephisino').
    February 03 2012 : Corrected few typos [no additional information]

    License

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    About the Author

    Lakamraju Raghuram
    Software Developer
    India India
    _____________________________________________________________
     
    Did my masters from IIT-M in Advanced Manufacturing Technology and working mainly on C++ in CAD domain from 2004 onwards.

    Comments and Discussions

     
    GeneralMy vote of 5 PinmemberAshish Tyagi 408-Feb-12 0:11 
    GeneralRe: My vote of 5 PinmemberLakamraju Raghuram8-Feb-12 0:24 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    | Advertise | Privacy | Mobile
    Web04 | 2.8.140721.1 | Last Updated 3 Feb 2012
    Article Copyright 2012 by Lakamraju Raghuram
    Everything else Copyright © CodeProject, 1999-2014
    Terms of Service
    Layout: fixed | fluid