📜 ⬆️ ⬇️

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, 
 it now 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 adjust to the standard. Also, such a time of "radio silence" allowed the Committee to get feedback on the document. At the end of this period, the ANSI Standards Committee released an updated specification containing fixes and various improvements. These corrections were documented in the first technical list of errors from 2003.
')


Further, members began accepting proposals for changes to C ++. This initiative was called C ++ 0x, as it was expected that the 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 would not be able to be ratified earlier than in 2009, so the initiative changed its name to C ++ 09.

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

The standards 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, the final version of the document should be available in 2008, and its ratification will take place somewhere in 2009.

C ++ Philosophy 09



After ratifying C ++ 98 about a decade ago, the Standards Development 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 newbies to learn. Many programmers do not wish 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 accomplishing their tasks. Despite the addition of powerful new tools to the language, the main goal is still to simplify it.

Another goal is to safely upgrade the standard library before changing the core of the language itself. Changes in the core are very risky and can lead to huge compatibility problems. On the contrary, library improvements allow for greater flexibility with less risk. Take, for example, the implementation of the garbage collector: changing the core of the language for self-cleaning (as done in Java and C #) will lead to much more serious changes and 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 tried to improve real-world performance wherever possible. One of the strengths of C ++ is its performance (relative to new C # and Java). That is why many programmers choose C ++ as their main 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 something it is not.

An instructive tale of EC ++



In 1999, a consortium of developers of embedded systems in Japan (including NEC, Hitachi, Fujitsu and Toshiba) provided a proposal for the allocation of a subset of C ++. This subset would largely repeat C ++, with the exception of removing a number of features of the language, which, according to the consortium participants, were very complex and caused a great loss of performance. 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 members, 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 templates were used in most of the standard library, and removing them seemed completely impractical. At the same time, the consortium announced that it is possible the emergence of extended (extended) EC ++, which will support the patterns.

When the extended EC ++ compilers became available, they were again compared with their large counterparts. To the surprise of the consortium members, the performance gain compared to C ++ was not significant. Part of the problem was that the consortium was neglecting the C ++ principle “you don’t need 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 EC ++ fiasco, tried to determine what C ++ features really have big performance problems. 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 appears 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. As for RTTI and exception handling, many compilers have switches that allow them to be disabled. 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 the removal of some features of the language is comparable to their disabling.

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

Corrections and improvements



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

  vector <vector <int >> xv;  // Quite possible!
 vector <double> xv {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 broadcast units 




If you do not know why the above errors occur, then 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 <int I>
 struct myX
 {
      static int const x = 2;
 }
 
 template <>
 struct myX <0>
 {
      typedef int x;
 }
 
 template <typename T>
 struct myY
 {
      static int const x = 3;
 }
 
 static int const x = 4;
 
 cout << (myY <myX <1 >> :: x> :: x> :: x) << endl;  // C ++ 98 will display "3", and C ++ 09 - "2" 


Sync with ANSI / ISO C99



A year after the ratification of C ++, the ANSI / ISO C specification was updated with a small number of changes to the C language. Many of these changes already took place in C ++, but they also made sense in C. Others, on the contrary, 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, usually used for 64-bit numbers
 int16_t, int32_t, intptr_t, etc.  // Specific types of numbers
 double x = 0x1.F0 // Hex floating point numbers
 Comprehensive versions of some mathematical functions
 Macros that take an unfixed number of arguments 




C ++ Standard Library Improvements



A 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 to the user. C ++ 09 fills these gaps with the following new library classes:

  regex: expected regular expression class
 array <>: a one-dimensional array containing its own size (maybe 0)
 tuple <>: templated tuple class
 STL hash container classes: unordered_set <>, unordered_map <> 




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

Streamlining



Local storage:

  thread int x = 1;  // Globally Within The Flow 




Atomic operations:

  atomic
 {
	 // Suspends 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 at this point parallel blocks will only be unprofitable, it will simply execute them in a row.

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

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

Patterns with different number of arguments



For many years, C has allowed functions to have a non-fixed 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:

  // Display to stderr only when the DEBUG flag is set
 template <typename TypeArgs>
 void DebugMessage (TypeArgs ... args)
 {
	 #ifdef DEBUG
		 // Implementing an entry in stderr
	 #else
		 //Nothing to do
	 #endif
 }

 // Next in the 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 designers



Other languages, such as C #, allow one class constructor to call another. In C ++ 98, this possibility was absent, 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 the pointer
            MyClass (int myvalue);  // Gets a numeric value
 };
 
 MyClass :: MyClass (): MyClass (NULL) // Calls X (void *)
 {
     ... // Code
 }
 
 MyClass :: MyClass (void * myptr): MyClass (0) // Calls X (int)
 {
      ... // Code
 }

 MyClass :: MyClass (int myvalue) // Not Delegated
 {
      ... // Code
 } 




Null pointers



In ANSI C, NULL is defined as (void *) 0. In C ++, using 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 ++
                                     // Cannot add void * to int * in C ++!
 int * viPtr = 0;  // Correct in C ++ 




However, NULL propagation 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 the appearance of a cast error. Despite all the "courtesy" of compilers, all this greatly confuses novice C ++ programmers.

  void bar (int);  // Get the integer value
 void bar (char *);  // Gets the 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;  // Wrong
 myX * xPtr = nullptr;  // Can use with pointers of any type
 
 void bar (int);  // Get the integer value
 void bar (char *);  // Gets the char *
 bar (0);  // Calls foo (int)
 bar (nullptr);  // Calls foo (char *) 




Where have you been, auto?



When the C language was just being developed, the auto keyword was used to tell the compiler about the location of the 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 removed:

  auto x;  / * Wrong in ANSI C * /
 int x;  /* Right */
 auto int x;  / * True, true superfluous * / 




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

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




Cost effectiveness becomes more apparent when used together with complex species, such as the one below:

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




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

  void bar (vector <MySpace :: MyClass *> x)
 {
      for (auto ptr = x.begin (); ptr! = x.end (); ptr ++)
      {
          ... // Different kind of code
      }
 } 




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

What's interesting to note is that in C #, a similar behavior is created using the var keyword.

It should be noted that initialization is still necessary to use auto in C ++ 09:

  auto x;  // Wrong in C ++ 09 




But suppose you knew which type you needed (based on another variable), but did not want to initialize? The new decltype keyword is available for such purposes as, for example, in the following piece of code:

  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. Virtually 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 only memory owner:

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




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

The standard C ++ 09 library introduces a smarter pointer look: shared_ptr <>. Its main difference from auto_ptr <> is that it uses a distributed rights model and a reference counter for determining the time of memory release. For example:

  main ()
 {
      shared_ptr <int> ptr1;  // Smart NULL pointer
      ...
      {
           shared_ptr <int> ptr2 (new int [1024]);
           ptr1 = ptr2;  // Distribution of possessions (feudal)
      }
      // ptr2 removed, only ptr1 remained
      // Memory still not freed
 }
 // ptr1 removed, 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> (T * ptr);  // Attach to memory
 shared_ptr <T> (T * ptr, Fcn delFcn);  // Memory Attachment and Custom Purge Function 
 shared_ptr <T> (shared_ptr <T> ptr);  // Copy Constructor
 shared_ptr <T> (auto_ptr <T> ptr);  // Conversion with auto_ptr <> 




It should be noted 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 functions 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 language, function parameters are always passed by value (by value), that is, a copy of the parameter is passed, but its actual value is not. To change a variable in C, the function must pass a pointer, as in the example:

  void foo (int valueParameter, int * pointerParameter)
 {
        ++ valueParameter;  // Parameter is passed by value, 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 (by reference) using the “ & ” operator. This made it possible to modify the parameter data directly, without using pointers.

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




Links must be applied to lvalues ​​(as 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 rvalue and cannot be transmitted
 foo (0, myIntB + 1);  // Error: myIntB + 1 is rvalue and cannot be passed 




Sometimes it is useful to pass a parameter by reference even when it is not necessary to change its contents. This is especially true when large classes or structures are transferred to a function and copying such huge objects should be avoided.

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




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

  void foo (int valueParameter, int & lvalRefParameter, int && rvalRefParameter)
 {
        ++ valueParameter;  // Parameter is passed by value, all changes are local
        ++ lvalRefParameter;  // lvalue link, all changes are permanent
        ++ rvalRefParameter;  // Rvalue link, local changes without creating a copy
 }
 
 foo (0, myIntA, myIntB + 1);  // The temporary value of 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 moving, that is, moving data from one variable to another without copying. The class may define a motion constructor instead of or together with the copy constructor.

  // class definition
 class X
 {
     public:
            X ();  // Default constructor
            X (const X & x);  // Copy Constructor (lvalue link)
            X (X && x);  // Move constructor (rvalue link)
 };
 
 // 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, the memory moves directly to x3 




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

  void SwapData (vector <string> & v1, vector <string> & v2)
 {
      vector <string> temp = v1;  // New copy v1
      v1 = v2;  // New copy v2
      v2 = temp;  // New copy temp
 }; 




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

  void SwapData (vector <string> & v1, vector <string> & v2)
 {
      vector <string> temp = (vector <string> &&) v1;  // temp - the same data as v1
      v1 = (vector <string> &&) v2;  // v1 contains v2
      v2 = (vector <string> &&) temp;  // v2 points to temp data
 }
         
 // No copy has been made, only moves! 




Other additions in C ++ 09



In addition to the features described, here is a list of some other changes:

New character types : chart16_t, char32_t


Static statements (asserts, from Boost ::)
Linking (aliasing) templates
Type checking : is_pointer (), is_same ()
Foreach introduction
New random number generator


findings



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

Source: https://habr.com/ru/post/25330/


All Articles