Abstract Introduction 1. auto 2. decltype 3. Temporary object reference (R-value reference) 4. Right angle brackets 5. Lambdas 6. Suffix return type syntax 7. static_assert 8. nullptr 9. New standard classes 10. New directions in the development of static code analyzers Conclusion Bibliographic listannotation
The article discusses the new features of the C ++ language described in the C ++ 0x standard and supported in Visual Studio 2010. Using PVS-Studio as an example, we examined how language changes will affect static code analysis tools.
Introduction
The new C ++ language standard is about to come into our lives. While it continues to be called C ++ 0x, although, apparently, its final name is C ++ 11. The new standard is already partially supported by modern C ++ compilers, for example Intel C ++ and Visual C ++. Support is far from complete, which is quite natural. Firstly, the standard has not yet been adopted, and secondly, even when it is adopted, it will take time to work out its features in compilers.
Compiler developers are not the only ones for whom support for the new standard is important. Language innovations should be quickly supported in the tools of static analysis of the source code. The new standard promises backward compatibility. Almost guaranteed, the old C ++ code will be correctly compiled by the new compiler without the need for any corrections. However, this does not mean that a program that does not contain new language constructs can still be processed by a static analyzer that does not support the new C ++ 0x standard. We made sure of this in practice, trying to verify using
PVS-Studioa project created in the beta version of Visual Studio 2010. It's all about the header files that already use the new language constructs. For example, in the header file “stddef.h” you can see the use of the new decltype operator:
namespace std {typedef decltype (__ nullptr) nullptr_t; } |
Naturally, such constructions are syntactically incorrect for an analyzer that does not support C ++ 0x, and lead either to a halt in its operation or an incorrect result. It became obvious that PVS-Studio needed to support C ++ 0x by the time Visual Studio 2010 was released, at least to the extent that the new standard was supported by this compiler.
It can be stated that this problem was successfully solved by us and at the time of writing, the site has a version of PVS-Studio 3.50 available that integrates both in Visual Studio 2005/2008 and in Visual Studio 2010. Starting from version PVS-Studio 3.50 in the tool Support for the part of C ++ 0x implemented in Visual Studio 2010 is implemented. Support is not ideal, as for example, when working with "right-angle brackets", but we will continue to work on supporting the C ++ 0x standard in future versions.
In this article we will consider the new features of the language, the support of which is implemented in the first edition of Visual Studio 2010. At the same time, we will look at these features from different perspectives: what is the new feature, is there a connection with 64-bit errors, how was the new language design It is supported in PVS-Studio and how its appearance was reflected in the
VivaCore library .
Note. VivaCore - a library for parsing, analyzing and transforming code. VivaCore is an open library and supports C and C ++ languages. PVS-Studio was built on the basis of VivaCore and other software projects can be created on its basis .
This article can be called a report on research and support of the new standard in PVS-Studio. PVS-Studio tool diagnoses 64-bit and parallel
OpenMP errors. But since the transition to 64-bit systems is currently a more urgent topic, preference will be given to examples demonstrating the detection of
64-bit errors using PVS-Studio .
1. auto
In C ++, as in C, the type of the variable must be specified explicitly. However, with the advent in C ++ of template types and template metaprogramming techniques, a situation has become frequent when the type of an object is not so simple to write. Even in a fairly simple case, when iterating over elements of an array, we will need to declare an iterator type of the form:
for (vector:: iterator itr = myvec.begin ();
itr! = myvec.end ();
++ itr) |
Such designs are very long and uncomfortable. You can use typedef to reduce the record, but this creates new entities and adds little in terms of convenience.
C ++ 0x offers a way to mitigate this problem. In the new standard, the meaning of the keyword auto will be replaced. If earlier auto meant that the variable was created on the stack, and was implied implicitly if you did not specify something else (register, for example), now it is an analogue of var in C # 3.0. The type of a variable declared as auto is determined by the compiler independently based on how this variable is initialized.
It should be noted that an auto variable will not be able to store values of different types during one program run. C ++ is still a statically typed language, and the indication auto only tells the compiler to take care of determining the type on its own: after initialization, changing the type of the variable will no longer be possible.
Now the iterator can be declared as follows:
for (auto itr = myvec.begin (); itr! = myvec.end (); ++ itr) |
In addition to the convenience of writing code and its simplification, the auto keyword will help make the code more secure. Let's look at an example where auto will make the code safe from the point of view of creating 64-bit applications:
bool Find_Incorrect (const string * arrStr, size_t n)
{
for (size_t i = 0; i! = n; ++ i)
{
unsigned n = arrStr [i] .find ("ABC");
if (n! = string :: npos)
return true;
}
return false;
}; |
This code contains a 64-bit error. The function behaves correctly when compiling the
Win32 version and crashes when building in
Win64 mode . The error is to use the unsigned type for the variable "n", although the type string :: size_type that the find () function returns must be used. In a 32-bit program, the types string :: size_type and unsigned coincide, and we get the correct results. In a 64-bit program, string :: size_type and unsigned cease to match. When the substring is not found, the find () function returns a string :: npos equal to 0xFFFFFFFFFFFFFFFFFFui64. This value is truncated to 0xFFFFFFFFu and placed in a 32-bit variable. As a result, the condition 0xFFFFFFFFFFu == 0xFFFFFFFFFFFFFFFFui64 is false and it turns out that the Find_Incorrect function always returns true.
In this example, the error is not so terrible, it is detected even by the compiler and the more specialized Viva64 analyzer (included in PVS-Studio).
Compiler:
warning C4267: 'initializing':
conversion from 'size_t' to 'unsigned int', possible loss of data |
Viva64:
V103: Implicit type conversion from memsize to 32-bit type. |
More importantly, this error is possible and often occurs in the code due to carelessness when choosing the type for storing the return value. It is even possible that the error arose because of the unwillingness to use the cumbersome construct like string :: size_type.
Now, these errors are easily avoided, without cluttering the code. Using the “auto” type, we can write the following simple and reliable code:
auto n = arrStr [i] .find ("ABC");
if (n! = string :: npos)
return true; |
The error disappeared by itself. The code has not become more complicated or less efficient. Conclusion - the use of “auto” is rational in many cases.
The keyword “auto” will reduce the number of 64-bit errors or allow correcting errors more elegantly. But the use of “auto” alone does not at all eliminate all 64-bit errors! This is just another language tool that makes life easier for the programmer, but does not do all the work of type control for it. Consider an example:
void * AllocArray3D (int x, int y, int z,
size_t objectSize)
{
int size = x * y * z * objectSize;
return malloc (size);
} |
The function should calculate the size of the array and allocate the required amount of memory. It is logical to expect that in a 64-bit environment this function will be able to allocate memory for working with an array of size 2000 * 2000 * 2000 of the double type. However, a call of the form “AllocArray3D (2000, 2000, 2000, sizeof (double));” will always return NULL, as if allocating such an amount of memory is not possible. The real reason why the function returns NULL is an overflow error in the expression "int size = x * y * z * sizeof (double)". The variable "size" will take the value -424509440 and further call to the malloc function does not make sense. By the way, the compiler will warn about the danger of this expression:
warning C4267: 'initializing':
conversion from 'size_t' to 'int', possible loss of data |
Hoping for “auto”, a sloppy programmer can modify the code as follows:
void * AllocArray3D (int x, int y, int z,
size_t objectSize)
{
auto size = x * y * z * objectSize;
return (double *) malloc (size);
} |
However, this does not eliminate at all, but only disguises the error. The compiler will no longer issue a warning, but the AllocArray3D function will still return NULL.
The type of the variable "size" will automatically become "
size_t ". But overflow occurs when evaluating the expression "x * y * z". This subexpression is of type "int" and only then the type will be expanded to "size_t" when multiplied by the variable "objectSize".
Now this hidden error can be detected only using the Viva64 analyzer:
V104: Implicit type conversion to memsize type in an
arithmetic expression. |
Conclusion - using "auto", you should still be careful.
Now let's briefly look at how the new keyword was supported in the VivaCore library, on which the Viva64 static analyzer is built. So, the analyzer should be able to understand that the variable AA is of type “int” in order to warn (see
V101 ) that the variable AA is expanded to type “size_t”:
void Foo (int X, int Y)
{
auto AA = X * Y;
size_t BB = AA; // V101
} |
First of all, a new token table was compiled that included the new C ++ 0x keywords. This table is in the Lex.cc file and has the name tableC0xx. In order not to modify the old code for processing the token “auto” (tkAUTO), the token “auto” in this table has the name tkAUTOcpp0x.
In connection with the appearance of a new token, the following functions underwent modifications: isTypeToken, optIntegralTypeOrClassSpec. The new LeafAUTOc0xx class has appeared. TypeInfoId introduced a new class of objects - AutoDecltypeType.
For coding of type “auto”, the letter 'x' was selected, which was reflected in the functions of the TypeInfo and Encoding classes. These are, for example, functions such as IsAutoCpp0x, MakePtree.
These corrections allow you to parse code with the key “auto”, which has a new meaning and save the type of objects in encoded form (letter 'x'). However, this does not allow us to know what type the variable actually represents. That is, VivaCore lacks functionality that allows you to find out that in the expression “auto AA = X * Y” the variable AA will be of type “int”.
This functionality is contained in the Viva64 source code and is not included in the VivaCore library code. The principle is the extra work of computing the type in the TranslateAssignInitializer method. After the right part of the expression is calculated, the Bind of the variable name with the type is replaced.
2. decltype
In some cases, it is useful to “copy” the type of an object. The keyword “auto” infers a type based on the expression used to initialize the variable. If there is no initialization, then the keyword “decltype” can be used to determine the type of expression during compilation. Sample code where the variable "value" will have the type returned by the function "Calc ()":
decltype (Calc ()) value;
try {
value = Calc ();
}
catch (...) {
throw;
} |
You can use decltype to declare a type:
void f (const vector& a,
vector& b)
{
typedef decltype (a [0] * b [0]) Tmp;
for (int i = 0; i |
Note that a type taken using decltype may differ from a type deduced using auto.
const std :: vector v (1);
auto a = v [0]; decltype (v [0]) b = 1;
// type a - int
// type b - const int & (return value
// std :: vector:: operator [] (size_type) const) |
Let's move on to an example where “decltype” can be useful in terms of 64-bit. The IsPresent function searches for an element in a sequence and returns true if it is found:
bool IsPresent (char * array,
size_t arraySize,
char key)
{
for (unsigned i = 0; i <arraySize; i ++)
if (array [i] == key)
return true;
return false;
} |
This function is unable to work in a 64-bit system with large arrays. If the variable arraySize has a value greater than UINT_MAX, then the condition "i <arraySize" will never be fulfilled and an eternal cycle will occur.
If we use the keyword "auto", this will not change anything:
for (auto i = 0; i <arraySize; i ++)
if (array [i] == key)
return true; |
The variable "i" will be of type "int", since 0 is of type "int". The correct fix might be to use "decltype":
for (decltype (arraySize) i = 0; i <arraySize; i ++)
if (array [i] == key)
return true; |
Now the counter “i” has type “size_t” as well as the variable “arraySize”.
Support for decltype in VivaCore library is very similar to support for auto. Added new tkDECLTYPE token. Added parsing function rDecltype in the file Parser.cc. In connection with the appearance of a new token, the optIntegralTypeOrClassSpec function was modified. A new LeafDECLTYPE class has appeared.
To encode the type returned by the decltype operator, the letter 'X' is selected (the capital letter 'X', as opposed to the uppercase 'x' used for auto). In this regard, the functionality of the TypeInfo and Encoding classes has changed. For example, WhatIs, IsDecltype, MakePtree functions.
Type calculation functionality for the decltype operator is implemented in the Environment class and is part of the VivaCore library. Type calculation is performed at the moment of writing a new variable / type in the Environment (functions RecordTypedefName, RecordDeclarator, RecordConstantDeclarator). The type calculation is performed by the FixIfDecltype function.
3. R-value reference
In the C ++ 98 standard, temporary objects can be passed in functions, but only as a constant reference (const &). Therefore, the function is not able to determine whether it is temporary or normal, which is also passed as const &.
In C ++ 0x, a new type of link will be added - a link to a temporary object (R-value reference). His announcement is: "TYPE_NAME &&". It can be used as a non-constant, legally modifiable object. This innovation allows you to take into account temporary objects and implement the transfer semantics (Move semantics). For example, if std :: vector is created as a temporary object or returned from a function, you can, by creating a new object, simply transfer all internal data from a link of a new type. The transfer constructor std :: vector through the resulting link to a temporary object simply copies the array pointer located in the link, which at the end is set to an empty state.
A hyphen constructor or hyphen can be declared as follows:
template class vector {
// ...
vector (const vector &); // copy constructor
vector (vector &&); // move constructor
vector & operator = (const vector &); // copy assignment
vector & operator = (vector &&); // move assignment
}; |
From the point of view of analyzing 64-bit errors in the code, it does not matter to us; it is processed when declaring type '&' or '&&'. Accordingly, support for this innovation in VivaCore is very simple. The changes affected only the optPtrOperator function of the Parser class. In it, we equally perceive both '&' and '&&'.
4. Right angle brackets
From the point of view of the C ++ 98 standard, the following construction contains a syntax error:
To prevent it, you must insert a space between two right closing angle brackets:
The C ++ 0x standard legalized the use of double closing brackets when declaring template types, without the need to insert a space between them. As a result, it becomes possible to write a little more elegant code.
Support for this innovation is important to implement in a static analyzer, since developers will gladly stop writing extra spaces.
At the moment, parsing declarations of template types with ">>" is not yet implemented in VivaCore in the best way. In some cases, the analyzer is mistaken and, apparently, over time, the analyzer parts associated with the analysis of the templates will be substantially reworked by us. While in the code you can see the following ugly functions that are trying to determine with heuristic methods, we are dealing with the shift operator ">>"
> D ": IsTemplateAngleBrackets, isTemplateArgs. For those who are interested in how to correctly approach the solution of this problem, the following document will be useful: " Right Angle Brackets (N1757) ." Over time, we will improve the processing of right angle brackets in VivaCore.
5. Lambda functions (Lambdas)
C ++ lambda expressions are a short form for writing anonymous functors (objects that can be used as functions). Consider a little history. In C, function pointers are used to create functors:
/ * callback function * /
int compare_function (int A, int B) {
return A <B;
}
/ * declaration of the sort function * /
void mysort (int * begin_items,
int num_items,
int (* cmpfunc) (int, int));
int main (void) {
int items [] = {4, 3, 1, 2};
mysort (items,
sizeof (items) / sizeof (int),
compare_function);
return 0;
} |
Earlier in C ++, a functor was created using a class with operator () overloaded:
class compare_class {
public:
bool operator () (int A, int B) {
return (A <B);
}
};
// declare a sort function
template
void mysort (int * begin_items,
int num_items,
ComparisonFunctor c);
int main () {
int items [] = {4, 3, 1, 2};
compare_class functor;
mysort (items,
sizeof (items) / sizeof (int),
functor);
} |
In C ++ 0x, we get the opportunity to declare a functor even more elegantly:
auto compare_function = [] (char a, char b)
{return a <b; };
char Str [] = "cwgaopzq";
std :: sort (Str,
Str + strlen (Str),
compare_function);
cout << Str << endl; |
We start the variable compare_function which is a functor and the type of which is determined automatically by the compiler. Then we can pass this variable to std :: sort. We can further reduce the code:
char Str [] = "cwgaopzq";
std :: sort (
Str
Str + strlen (Str),
[] (char a, char b) {return a <b;}
);
cout << Str << endl; |
Here "[] (char a, char b) {return a <b;}" is nothing more than a lambda function.
A lambda expression always begins with brackets [], in which a capture list can be specified. Then comes an optional parameter list and an optional return type. Completes the declaration directly the function body. In general, the format for writing lambda functions is as follows:
'[' [<capture list>] ']'
['(' <parameter list> ')' ['mutable']]
['throw' '(' [<exception types>] ')']
['->' <return_type_type>]
'{' [<function body>] '}' |
The capture list indicates which objects from the external scope are accessed by the lambda function:
- [] - without capturing variables from the external scope;
- [=] - all variables are captured by value;
- [&] - all variables are captured by reference;
- [x, y] - capture of x and y by value;
- [& x, & y] - capture x and y by reference;
- [in, & out] - capture in by value, and out - by reference;
- [=, & out1, & out2] - capture of all variables by value, except out1 and out2, which are captured by reference;
- [&, x, & y] - capture of all variables by reference, except x.
Unfortunately, within the framework of this article, it is not possible to devote more attention to lambda functions. You can learn more about lambda functions by visiting the resources listed in the bibliography at the end of the article. As a demonstration of the use of lambda functions, consider the code of a program that displays strings in increasing order of their length.
The program creates an array of strings and an array of indices. Then the program sorts the row indices so that the rows are arranged by increasing their length:
int _tmain (int, _TCHAR * [])
{
vector strings;
strings.push_back ("lambdas");
strings.push_back ("decltype");
strings.push_back ("auto");
strings.push_back ("static_assert");
strings.push_back ("nullptr");
vector indices;
size_t k = 0;
generate_n(back_inserter(indices),
strings.size(),
[&k]() { return k++; });
sort(indices.begin(),
indices.end(),
[&](ptrdiff_t i1, ptrdiff_t i2)
{ return strings[i1].length() <
strings[i2].length(); });
for_each(indices.begin(),
indices.end(),
[&strings](const size_t i)
{ cout << strings[i] << endl; });
return 0;
} |
Примечание.Согласно С++0x можно инициализировать массивы std::vector следующим образом:
vector indices = {0,1,2,3,4}; |
But while Visual Studio 2010 does not support such designs.
The quality of the analysis of lambda functions in static analyzers should correspond to the quality of the analysis of simple functions. In general, the analysis of lambda functions is similar to the analysis of simple functions, except that lambda functions have a different scope.
PVS-Studio implements full error diagnostics in lambda functions. Consider a code example containing a 64-bit error:
int a = -1;
unsigned b = 0;
const char str [] = "Viva64";
const char * p = str + 1;
auto lambdaFoo = [&] () -> char
{
return p [a + b];
};
cout << lambdaFoo () << endl; |
This code works when compiling in Win32 mode and prints the letter 'V' on the screen. In Win64 mode, the program crashes due to an attempt to access the element with the number 0xFFFFFFFF. Read more about this type of error in the lessons on developing 64-bit C / C ++ applications - " Lesson 13. Pattern 5. Address arithmetic ."
When checking the above code, PVS-Studio displays a diagnostic message:
error V108: Incorrect index type: p [not a memsize-type]. Use memsize type instead. |
Accordingly, the analyzer had to parse the lambda function and deal with the scope of variables. Difficult, but necessary functionality.
With the support of lambda functions, the most significant changes in VivaCore are connected. The new rLambdas function is now involved in the process of building the parse tree . The function is in the Parser class and is called from functions such as rInitializeExpr, rFunctionArguments, rCommaExpression. The rLambdas function parses lambda functions and adds a new type of object to the tree - PtreeLambda. The PtreeLambda class is declared and implemented in the PtreeLambda.h and PtreeLambda files.
Processing PtreeLambda in the constructed tree is performed by the TranslateLambda function. All logic for working with lambda functions is concentrated in VivaCore. Inside TranslateLambda, you will find the GetReturnLambdaFunctionTypeForReturn function call implemented in the PVS-Studio code. But this function is used for internal purposes by PVS-Studio and the empty GetReturnLambdaFunctionTypeForReturn function plug-in in VivaCore will not affect the code parsing.
6. Suffix return type syntax
There are times when it is difficult to specify the type returned by the function. Consider an example of a template function that multiplies two values:
template
??? mul (T x, U y)
{
return x * y;
} |
The return type must be the type of the expression "x * y". But, it is not clear what can be written instead of "???". The first idea might be to use "decltype":
template
decltype (x * y) mul (T x, U y) // Scope problem!
{
return x * y;
} |
The variables "x" and "y" are declared after "decltype (x * y)" and such code, unfortunately, cannot be compiled.
The solution to this problem is to use the new syntax of the return values:
template
[] mul (T x, U y) -> decltype (x * y)
{
return x * y;
} |
Using the brackets [], we generate here a lambda function and at the same time say "the return type will be deduced or specified later." Unfortunately, although the above example is correct, at the time of writing this article is not compiled in Visual C ++. However, we can use an alternative (where Suffix return type syntax is also used):
template
auto mul (T x, U y) -> decltype (x * y)
{
return x * y;
} |
This code will be successfully built by Visual C ++ and we will get the desired result.
In version PVS-Studio 3.50, support for the new function format is only partially implemented. VivaCore library fully understands the constructions, but PVS-Studio does not take into account the data types returned by these functions when analyzing. You can get acquainted with the support of alternative recording of functions in the VivaCore library in the Parser :: rIntegralDeclaration function.
7. static_assert
In the C ++ 0x standard, a new static_assert keyword has appeared. Syntax:
static_assert (expression, "error message"); |
If the expression is false, then the specified error message is displayed and compilation stops. Consider an example of using static_assert:
template
struct MyStruct
{
static_assert (n> 5, "N must be more than 5");
};
MyStruct <3> obj; |
When compiling this code, the Visual C ++ compiler will display a message:
error C2338: N must be more 5
xx.cpp (33): see reference to class template
instantiation 'MyStruct'being compiled
with
[
n = 3
] |
From the point of view of code analysis carried out by PVS-Studio, the static_assert construct is not of interest and therefore is ignored. VivaCore added new tkSTATIC_ASSERT token. Encountering this token, the lexer ignores it and all parameters related to the static_assert construct (implementation in the Lex :: ReadToken function).
8. nullptr
Prior to the C ++ 0x standard, C ++ did not have a keyword to indicate a null pointer. The number 0 was used to denote it. However, the use of the NULL macro was considered a good style. When expanded, the NULL macro becomes 0, and there is no practical difference between them. This is how the NULL macro is declared in Visual Studio:
In some cases, the lack of a special keyword to indicate a null pointer was inconvenient and even provoked errors. Consider an example:
void Foo (int a)
{cout << "Foo (int a)" << endl; }
void foo (char * a)
{cout << "Foo (char * a)" << endl; }
int _tmain (int, _TCHAR * [])
{
Foo (0);
Foo (NULL);
return 0;
} |
Although the programmer can expect that different functions of Foo will be called in this code, this is not so. Instead of NULL, 0 will be substituted with the type "int" and when the program starts, it will be printed on the screen:
To eliminate such situations, the nullptr keyword is introduced in C ++ 0x. The nullptr constant is of type nullptr_t and is implicitly cast to any type of pointer or pointer to class members. The nullptr constant is not implicitly cast to integer data types except for the "bool" type.
Let's go back to our example and add a call to the “Foo” function with the nullptr argument:
void Foo (int a)
{cout << "Foo (int a)" << endl; }
void foo (char * a)
{cout << "Foo (char * a)" << endl; }
int _tmain (int, _TCHAR * [])
{
Foo (0);
Foo (NULL);
Foo (nullptr);
return 0;
} |
Now the screen will print:
Foo (int a)
Foo (int a)
Foo (char * a) |
Although the nullptr keyword is not interesting from the point of view of searching for 64-bit errors, its support is needed when parsing the code. To do this, a new token tkNULLPTR was added to VivaCore, as well as the LeafNULLPTR class. Objects of type LeafNULLPTR are created in the rPrimaryExpr function. When the LeafNULLPTR :: Typeof function is called, the type "nullptr" is encoded as "Pv", that is, "void *". From the point of view of existing code analysis tasks in PVS-Studio, this is enough.
9. New standard classes
The C ++ 0x standard introduces new standard classes related to namespace std. A number of these classes are already supported in Visaul Studio 2010. An example is:
- std :: array;
- std :: shared_ptr;
- std :: regex.
Since the listed entities are ordinary template classes, their appearance did not require any modification of PVS-Studio or the VivaCore library.
10. New directions in the development of static code analyzers
In the end, I want to mention one interesting point related to the use of C ++ 0x. On the one hand, new features of the language, correcting old flaws, make the code safer and more efficient, but at the same time also create new, yet unknown traps that the programmer may fall into. True, I can’t tell anything about them yet.
But you can fall into the already known traps due to the fact that their diagnostics in the new C ++ 0x constructions are implemented much worse or not at all. Consider a small example demonstrating the use of an uninitialized variable:
{
int x;
std :: vector A (10);
A [0] = x; // Warning C4700
}
{
int x;
std :: vector A (10);
std :: for_each (A.begin (), A.end (),
[x] (int & y)
{y = x; } // No Warning
);
} |
The programmer can hope to receive a warning from the compiler in both the first and second cases. But in the example with the lambda function, no warning will be issued (tested on Visual Studio 2010 RC, / W4). As before, there were many other warnings for various dangerous situations. It takes time to implement detailed diagnostics.
We can expect a new round of development of static analyzers from the point of view of searching for potentially dangerous constructs that arise when using C ++ 0x constructs. We position our product PVS-Studio as a tool for checking modern programs. At the moment, we mean 64-bit and parallel technologies. In the future, we plan to conduct research on what potential problems can be expected when using C ++ 0x. If there are a lot of pitfalls, then perhaps we will begin to create a new tool for their diagnosis.
Conclusion
In our opinion, C ++ 0x brings a lot of good points. Old code does not require immediate modernization, although it can be modified over time during refactoring. New code may already be written using new constructs. Thus, starting to use C ++ 0x seems rational right now.
Bibliographic list
- Bjarne Stroustrup. C ++ 0x - the next ISO C ++ standard. http://www.viva64.com/go.php?url=304
- Visual C ++ Team Blog. Rvalue References: C ++ 0x Features in VC10, Part 2. http://www.viva64.com/go.php?url=305
- Sergey Olendarenko. C ++ 0x. Lambda expressions. http://www.viva64.com/go.php?url=306
- Maksim. C ++ 0x and solving initialization problems. http://www.viva64.com/go.php?url=307
- Wikipedia C ++ 0x. http://www.viva64.com/go.php?url=301