C ++ 2009

    “The most important thing in a programming language is its name. 
    A language will not succeed without a good name. 
    I recently came up with a very good name, 
    now it remains to invent a suitable language. ”  
    D. E. Knut  


    C ++ 09 evolution: flashback



    After the first C ++ specification, ratified in 1998, a five-year break was taken, which allowed compiler developers to adapt to the standard. Also, this time of “radio silence” allowed the Committee to receive feedback on the document. At the end of this period, the ANSI Standards Committee released an updated specification containing corrections and various improvements. These corrections were documented in the first 2003 technical error list.



    Further, members of the Committee began to accept proposals for changes to C ++. This initiative was called C ++ 0x, as it was expected that a new version of the language would be approved in the first decade of the twenty-first century. But over time, it became obvious: the new version of the language could not be ratified earlier than in 2009, so the initiative changed its name to C ++ 09.

    The development of a document on library extensions was launched in 2004 and completed in January 2005 (it was called TR1). It recommended introducing several extensions into the standard C ++ library, many of which came from the Boost framework. In April 2006, the Committee adopted all TR1 recommendations (with the exception of some high-level math libraries, which are difficult for compiler developers to implement). GCC 4.0 has already implemented most of TR1 in the std :: tr1 :: namespace. In addition to GCC, Metrowerks CodeWarrior 9 and 10 also did this. Microsoft released the Visual C ++ 2008 Feature Pack, which also implements TR1 (thanks to wasker ).

    The standards development committee plans to complete C ++ 09 by the end of 2007. In the same year, two meetings are planned in April and October. If there are no obstacles, then the final version of the document should be available in 2008, and its ratification will take place somewhere in 2009.

    Philosophy C ++ 09



    After ratifying C ++ 98 about a decade ago, the Standards Committee was not interested in making major changes to the language, but it supported changes that could make the language easier and more accessible for beginners to learn. Many programmers do not want to be experts in a particular programming language. On the contrary: they want to be professionals in their fields and simply use C ++ as a means of realizing their tasks. Despite the addition of powerful new tools to the language, the main goal still remains to simplify it.

    Another goal is to painlessly update the standard library before changing the core of the language itself. Changes to the kernel are very risky and can lead to huge compatibility issues. On the contrary, library improvements allow you to achieve great flexibility with less risk. Take, for example, the implementation of the garbage collector: changing the kernel of the language for self-cleaning (as is done in Java and C #) will lead to much more serious changes and will require additional backward compatibility, and the support of the smart pointer class in the standard library provides the programmer with similar opportunities at a lower cost.

    Finally, the Committee endeavored to improve real productivity wherever possible. One of the strengths of C ++ is its performance (relatively new C # and Java). That is why many programmers choose C ++ as their primary programming language. In 2003, according to IDC, there were about 3 million C ++ programmers, so it makes sense to improve the language for their convenience, rather than trying to turn it into what it is not.

    An instructive tale of EC ++



    In 1999, a consortium of Japanese embedded developers (including NEC, Hitachi, Fujitsu, and Toshiba) submitted a proposal to highlight a subset of C ++. This subset would largely repeat C ++, with the exception of removing a certain number of language features, which, according to consortium members, were very complex and caused great performance damage. The main components of the language that should be removed: multiple inheritance, patterns, exceptions, RTTI, new cast operators and namespaces. Such a subset of the language would be called Embedded C ++ (or simply EC ++).

    To the surprise of the consortium, EC ++ compilers were not faster than C ++ compilers. Quite the contrary: they were, in some cases, much slower! The founder of C ++, Bjarn Straustrup, explained that the templates were used in most of the standard library, and their removal looked completely impractical. At the same time, the consortium announced that it is possible the emergence of extended (extended) EC ++, which will support the templates.

    When the extended EC ++ compilers became available, they were again matched with their larger counterparts. To the surprise of the consortium, the performance gain compared to C ++ was negligible. Part of the problem was that the consortium neglected the C ++ principle "you don’t have to pay for what you don’t use." After that, ISO refused to accept any suggestions regarding EC ++.

    In 2004, the C ++ 0x Committee, inspired by the fiasco of EC ++, tried to determine which C ++ features really have big performance issues. As it turned out, there are only three areas where productivity could really be increased:

    new and delete
    RTTI (typeid () and dynamic_cast <>)
    exceptions (throw and catch)
    



    Memory allocation has turned out to have the greatest impact on performance, but it is unlikely that you would use a language that does not allocate memory from the heap. Regarding RTTI and exception handling, many compilers have switches to turn them off. In modern compilers, exception handling is implemented at a fairly high level and the problem lies only in RTTI. In any case, if you adhere to the principles of C ++, then removing some features of the language is comparable to disabling them.

    Regarding EC ++, Straustrup said: “In my opinion, EC ++ is dead, but if not, it must be dead .

    Fixes and improvements



    Despite the fact that the C ++ standard in 1998 was a striking achievement in itself, it had a small number of problems. Some were difficult to catch, others were known problems, but very often they were not enough to create a new resolution. Bjarn Straustrup explained some of them, for example:

    vector> xv; // Quite possible!
    vectorxv {1.2, 2.3, 3.4}; // Initialize STL Containers
    stronger typing of enum's // Enumerated types remain in their scope
    extern-ing of template's // No duplication among translation units




    If you do not know why the above errors occur, it is better not to try to understand the reason for their occurrence. I will consider only the first error. The disadvantage is that C ++ 98 parses the “>>” part of the vector as a right shift operator and generates an error. In C ++ 09, this error will be fixed. Here is a small example:

    template
    struct myX
    {
         static int const x = 2;
    }
    template <>
    struct myX <0>
    {
         typedef int x;
    }
    template
    struct myY
    {
         static int const x = 3;
    }
    static int const x = 4;
    cout << (myY> :: x> :: x> :: x) << endl; // C ++ 98 will output "3", and C ++ 09 - "2"


    Sync with ANSI / ISO C99



    A year after ratification of C ++, the ANSI / ISO C specification was updated with a few changes to the C language. Many of these changes have already taken place in C ++, but they also made sense in C. Others, by contrast, were not part of C ++, but the Committee considered them valuable and would try to reflect them in the C ++ 09 specification. These include:
    __func__ // Returns the name of the function in which it is located
    long long // Extended built-in type commonly used for 64-bit numbers
    int16_t, int32_t, intptr_t, etc. // Specific types of numbers
    double x = 0x1.F0 // Hexadecimal floating point numbers
    Complex versions of some mathematical functions
    Macros that take an unfixed number of arguments	




    C ++ Standard Library Enhancements



    The standard C ++ library (including STL) is a large number of useful containers and utilities. Despite the fullness of its capabilities, there were a number of components that were so necessary for the user. C ++ 09 fills these spaces with the following new library classes:

    regex: the regex class expected by all
    array <>: a one-dimensional array containing its own size (maybe 0)
    tuple <>: a tuple-tuple template class
    STL hash container classes: unordered_set <>, unordered_map <>




    Developers using GCC 4 (Xcode 2.x) may not wait until 2009 for such changes in the standard library, as they can use similar extensions through std :: tr1 ::.

    Stream improvement



    Local storage:

    thread int x = 1; // Globally within the thread




    Atomic operations:

    atomic
    {
    	// Suspend other threads at runtime
    }



    Parallel execution:

    active
    {
    	{...} // First parallel block
    	{...} // Second parallel block
    	{...} // Third parallel block
    }
    



    In the case of parallel execution, it is likely that if the compiler considers that in this place parallel blocks will only be unprofitable, he will execute them simply in a row.

    It is clear that such features of the language greatly simplify development that would otherwise be carried out using pthreads, mutexes, etc. It should be noted that the aforementioned characteristics are still being discussed by the members of the C ++ 09 Committee, so there may be slight changes.

    More information on such improvements can be found in this document .

    Templates with various number of arguments



    For many years, C has allowed functions to have an unfixed number of parameters. Unfortunately, this was not possible with C ++ 98. In C ++ 09, templates can have a variable number of types. Here is the simplest example:

    // Output to stderr only when the DEBUG flag is set
    template 
    void DebugMessage (TypeArgs ... args)
    {
    	#ifdef DEBUG
    		// Implementation of the entry in stderr
    	#else
    		//Nothing to do
    	#endif
    }
    // Further in code
    DebugMessage ("n is", n);
    DebugMessage ("x is", x, "y is", y, "z is", z);
    DebugMessage ("This is my trace:",
    		"time =", clock (),
    		"filename =", __FILE__,
    		"line number =", __LINE__,
    		"inside function:", __func__);




    Delegation of Constructors



    Other languages, such as C #, allow one class constructor to call another. In C ++ 98, this was not possible, which forced the class developer to create a separate initialization function. In C ++ 09, this becomes possible, as shown in the code below:

    class MyClass
    {
        public:
               MyClass (); // default constructor
               MyClass (void * myptr); // Gets a pointer
               MyClass (int myvalue); // Get a numeric value
    };
    MyClass :: MyClass (): MyClass (NULL) // Calls X (void *)
    {
        ... // The code
    }
    MyClass :: MyClass (void * myptr): MyClass (0) // Calls X (int)
    {
         ... // The code
    }
    MyClass :: MyClass (int myvalue) // Not Delegated
    {
         ... // The code
    }




    Null pointers



    In ANSI, C NULL is defined as (void *) 0. In C ++, NULL is not recommended. Why? Because, unlike C, in C ++ it is wrong to assign void pointers to pointers of any other type.

    void * vPtr = NULL; // Correct in both C and C ++
    int * viPtr = NULL; // Right in C, but wrong in C ++
                                        // You cannot attach void * to int * in C ++!
    int * viPtr = 0; // Right in C ++




    However, the spread of NULL in C ++ code is very large, so many compilers simply generate a warning (not an error) when such an assignment occurs. Others redefine NULL in C ++ as 0, thus preventing cast errors from occurring. Despite all the "courtesies" of compilers, all this greatly confuses novice C ++ programmers.

    void bar (int); // Gets an integer value
    void bar (char *); // Gets char *
    bar (0); // Is it a pointer or just a number?
    bar (NULL); // No corresponding prototype




    Thus, to simplify the use of null pointers, nullptr is introduced in C ++ 09. It can be used with pointers of any type, but cannot be applied to built-in types.

    char * cPtr1 = nullptr; // NULL pointer in C ++
    char * vcPtr2 = 0; // True, but not recommended
    int n = nullptr; // Invalid
    myX * xPtr = nullptr; // Can use with pointers of any type
    void bar (int); // Gets an integer value
    void bar (char *); // Gets char *
    bar (0); // Calls foo (int)
    bar (nullptr); // Calls foo (char *)




    Where have you been, auto?



    When C was just under development, the auto keyword was used to tell the compiler about the location of a variable on the stack, for example:

    auto x; / * A variable named x (integer) is located on the stack * /




    When ANSI C was ratified in 1989, the type definition was deleted:

    auto x; / * Invalid in ANSI C * /
    int x; /* Right */
    auto int x; / * True, the truth is superfluous * /




    Since then, auto has become a keyword in C (and later in C ++), although virtually no one has used auto since the 1970s. After three decades, the C ++ 09 standard reintroduces the auto keyword. The variable defined under this keyword will automatically acquire a type upon initialization.

    auto y = 10.0; // y is a floating point number
    auto z = 10LL; // z is long long
    const auto * p = & y; // p is const double *




    Profitability becomes more apparent when used in conjunction with complex views, such as below:

    void * bar (const int doubleArray [64] [16]);
    auto myFcnPtr = bar; // myFcnPtr now has type "void * (const int (*) [16])"




    On top of that, auto becomes very useful for temporary variables whose type is not so important. Consider the following function that goes through the elements of an STL container:

    void bar (vector x)
    {
         for (auto ptr = x.begin (); ptr! = x.end (); ptr ++)
         {
             ... // Various kinds of code
         }
    }




    Without the auto keyword, the type for the ptr variable would be vector:: iterator. In addition, any change in this container, for example, changing it from vector <> to list <>, or changing the class name, namespace name will certainly force the programmer to change the definition of the ptr variable, despite the fact that its type is absolutely not important within the loop .

    Interestingly, in C #, a similar behavior is created using the var keyword.

    It should be noted that initialization is still necessary for using auto in C ++ 09:

    auto x; // Invalid In C ++ 09




    But suppose you knew what type you needed (based on another variable), but didn't want to initialize? The new decltype keyword is available for purposes such as in the following code snippet:

    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;




    Smart pointers



    Smart pointers are objects that can themselves understand the time when they should remove themselves from memory and not rely on the programmer. Almost all modern languages, such as Java and C #, manage memory in accordance with a similar model, which avoids unnecessary memory leaks. In C ++ 98, there was a small similar object, auto_ptr <>. Unfortunately, auto_ptr <> has some limitations, the most notable of which is the use of its own access distribution model. That is, the last auto_ptr <> was the sole owner of the memory:

    auto_ptr ptr1 (new int [1024]); 
    auto_ptr ptr2 = ptr1;




    Because of this, in the C ++ community, the number of uses of auto_ptr <> tends to zero.

    The C ++ 09 standard library introduces a smarter pointer view: shared_ptr <>. Its main difference from auto_ptr <> is that it uses a distributed rights model and a reference counter to determine when to free memory. For instance:

    main ()
    {
         shared_ptrptr1; // Smart NULL pointer
         ...
         {
              shared_ptr ptr2 (new int [1024]);
              ptr1 = ptr2; // Distribution of possessions (feudal)
         }
         // ptr2 deleted, only ptr1 left
         // Memory still not freed
    }
    // ptr1 deleted, memory freed




    shared_ptr <> can be considered as a pointer, so it can be used as * ptr, and can be used in constructions like ptr1-> foo ().

    explicit shared_ptr(T * ptr); // Attach to memory
    shared_ptr(T * ptr, Fcn delFcn); // Attach to memory and custom clear function
    shared_ptr(shared_ptrptr); // Copy constructor
    shared_ptr(auto_ptrptr); // Convert with auto_ptr <>




    It is worth noting that the last constructor converts data from auto_ptr <> to shared_ptr <>, which greatly facilitates the transition from previous versions of the code and provides backward compatibility. Some additional features are provided, such as swap (), static_pointer_cast (), and dynamic_pointer_cast ().

    shared_ptr <> is already part of the std :: tr1 :: namespace and Mac programmers can use it through Xcode 2.x or higher.

    Rvalue Links



    In C, function parameters are always passed by value, that is, a copy of the parameter is passed, but its value is not relevant. To change a variable in C, the function must pass a pointer, as in the example:

    void foo (int valueParameter, int * pointerParameter)
    {
           ++ valueParameter; // The parameter is passed by value, the local copy is modified
           ++ pointerParameter; // The pointer is passed by value, but the local copy is modified anyway
           ++ * pointerParameter; // This change remains constant
    }




    One of the most powerful features of C ++ was passing parameters by reference using the & operator . This allowed you to modify the parameter data directly, without using pointers.

    void foo (int valueParameter, int & referenceParameter)
    {
           ++ valueParameter; // The parameter is passed by value, the local copy is modified
           ++ referenceParameter; // Pass by reference, so the changes remain constant
    }




    Links should be applied to lvalues ​​(since these are variables that can be modified), not rvalues ​​(which are read-only).

    int myIntA = 10;
    int myIntB = 20;
    foo (myIntA, myIntB); // myIntA = 10, myIntB = 21
    foo (1, myIntA); // 1 passed by value, myIntA = 11
    foo (myIntA, 1); // Error: 1 is an rvalue and cannot be passed
    foo (0, myIntB + 1); // Error: myIntB + 1 is an rvalue and cannot be passed




    It is sometimes useful to pass a parameter by reference even when its contents do not need to be changed. This is an especially true decision when large classes or structures are passed into a function and copying such huge objects should be avoided.

    void foo (BigClass valueParameter, const BigClass & constRefParameter)
    {
         ++ valueParameter; // Passed by value, changes are temporary
         ++ constRefParameter; // Error: unable to change constant parameter
    }




    In C ++ 09, a new type of link is introduced, which is called an rvalue link (therefore, the familiar link type in C ++ 98 will now be called an lvalue link). Rvalue links can be attached to temporary data, but they can be changed directly, without copying. The && operator says that the link is this rvalue link:

    void foo (int valueParameter, int & lvalRefParameter, int && rvalRefParameter)
    {
           ++ valueParameter; // The parameter is passed by value, all changes are local
           ++ lvalRefParameter; // Lvalue link, all changes are permanent
           ++ rvalRefParameter; // Rvalue link, local changes without the need for a copy
    }
    foo (0, myIntA, myIntB + 1); // The temporary value myIntB + 1 is not copied, but can be passed




    One of the main advantages of rvalue links is the ability to take advantage of the semantics of movement, that is, moving data from one variable to another without copying. A class can define a move constructor instead of or together with a copy constructor.

    // class definition
    class X
    {
        public:
               X (); // default constructor
               X (const X & x); // Copy constructor (lvalue reference)
               X (X && x); // Move constructor (rvalue reference)
    };
    // Various functions returning X
    X bar (); 
    X x1; // Create an x1 object using the default constructor
    X x2 (x1); // x2 becomes a copy of x1
    X x3 (bar ()); // bar () returns a temporary X, memory moves directly to x3




    The primary motivation for the semantics of movement is an increase in productivity. Suppose we have two row vectors, the data between which we want to swap. Using the standard copy logic, we get the following code:

    void SwapData (vector & v1, vector & v2)
    {
         vectortemp = v1; // New copy v1
         v1 = v2; // New copy v2
         v2 = temp; // Novia copy of temp
    };




    Using the logic of movement, we get something like this:

    void SwapData (vector & v1, vector & v2)
    {
         vector temp = (vector &&) v1;	// temp — те же данные, что v1
         v1 = (vector &&) v2;			// v1 содержит v2
         v2 = (vector &&) temp;			// v2 указывает на данные temp
    }
    // Не было произведено ни одного копирования, только перемещения!




    Другие добавления в C++09



    Кроме описанных возможностей, здесь представлен список некоторых других изменений:

    Новые типы символов: chart16_t, char32_t


    Статичные утверждения ( asserts, from Boost:: )
    Связывание (aliasing) шаблонов
    Проверка типов: is_pointer(), is_same()
    Введение foreach
    Новый генератор случайных чисел


    Выводы



    Many changes to the next version of C ++ are available to programmers now, due to the fact that they relate to the standard library. Despite this, preparing yourself for the upcoming update of the language is now worth it. Reading about all these changes, it becomes clear that C ++ has a rather interesting future.

    Also popular now: