When you want to upgrade your version of the Visual C ++ compiler (for example, to switch from Visual Studio from 2013 to 2015), it will not be superfluous to know why you may encounter that the code that was successfully compiled and executed before will now cause compilation errors and / or runtime errors. These problems can be caused by numerous compiler changes to conform to the C ++ standard, changes in function signatures, or changes in the location of objects in memory. In order to avoid runtime errors (which are known to be the most difficult to find), we recommend never doing static linking with binary files obtained by another version of the compiler. Also when updating your program (EXE or DLL), make sure that the libraries used are also compiled with the new version of the compiler. If you use types from CRT (C Runtime) or STL (Standard Template Library), do not transfer them between binary files (including DLLs) that are compiled by different versions of the compiler. This issue is discussed in more detail in Potential Errors Passing CRT Objects Across DLL Boundaries . And in the future, we recommend not to write code that depends on the specific location of objects in memory (if it is not a COM interface or a POD object). If you now have such code, after updating the compiler you should make sure that everything works as it should. More details can be found here: Portability At ABI Boundaries (Modern C ++) .
The following article describes the changes in the Visual C ++ compiler (which comes with Visual Studio 2015 Preview). In the article, the words “new behavior” and “now” refer specifically to this version, and “old behavior” and “earlier” refer to Visual Studio 2013 (and earlier versions).
Summary: - Changes in the compiler - Changes in C Runtime Library (CRT) - STL changes - Changes in MFC and ATL ')
Compiler Changes
/ Zc: forScope - The compiler flag /Zc:forScope- been deprecated and will be removed in the future. Now the compiler using this flag will throw out the D9035 warning. This flag is used to use a non-standard C ++ extension — using variables declared in the description of a for loop outside of this loop. This flag is necessary only if another flag is set - /Za ( comply with the standard ), because without /Za , the use of variables from the description of the loop is allowed by default. If you do not need to worry about cross-platform (for example, you are not supposed to collect code from other compilers), you can turn off the /Za flag (set the “Disable Language Extensions” project property to “No”). If you care about cross-platform and standard compliance, then such parts of the code need to be rewritten by moving the variable declaration above the loop:
// zc_forScope.cpp // compile with: /Zc:forScope- /Za // C2065 expected int main() { // // int i; for (int i =0; i < 1; i++) ; i = 20; // /Za i }
/ Zg The /Zg compiler flag ( prototyping functions ) is no longer available for use (it used to have the deprecated attribute)
Now you cannot run unit tests using C ++ / CLI from the command line using mstest.exe, instead you need to use vtest.console.exe. You can learn more about this here: VSTest.Console.exe command-line options .
Keyword mutable Now the use of mutable , in accordance with the standard, is allowed only applicable to the names of class members, and can not be applied to links, or names declared as const or static . Example:
structS {mutableint &r; };
Previously, this was compiled, now the compiler will generate error C2071. To fix, you just need to remove the mutable .
char_16_t and char_32_t Now you cannot use char_16_t and char_32_t as aliases for custom types, because now these types are defined as built-in. It used to be quite common practice for library authors to define char_16_t and char_32_t as aliases for uint_16_t and uint_32_t, respectively.
#include<cstdint> typedef uint16_t char16_t; //C2628 typedef uint32_t char32_t; //C2628 int main(int argc, char* argv[]) { uint16_t x = 1; uint32_t y = 2; char16_t a = x; char32_t b = y; return 0; }
To fix it, remove the alias declaration and rename any other identifiers that conflict with the newly entered ones.
Non-type (non-type) template parameters Code that includes atypical template parameters is now correctly checked for type compatibility. For example, the following code was previously compiled without errors:
Now the compiler will generate an error, since the type of the template parameter does not match the type of the argument passed (the type of the parameter is a pointer to a constant method, but f is not constant). error C2893: Failed to specialize function template 'void S2::f(void)' note: With the following template arguments: note: 'C=S1' note: 'Function=S1::f'
To get rid of this error, make sure that the type of the template argument matches the type of the parameter.
__declspec (align) The compiler no longer accepts __declspec(align) for functions. In truth, he never accepted, but now he will give out an error C3323. To get rid of it, simply remove this expression from the function declaration. Since this has not had any effect before, it will not change anything in your program.
Exception Handling There are several changes in exception handling. The first is that exception objects must be copied and moved. before this code was compiled, now there will be an error:
The problem here is that the copy constructor is declared private, so the object cannot be copied, which is usually required when processing an exception. The same applies when the constructor is declared explicit .
To get rid of this problem, make sure that the constructor for the exception object is declared in a public zone and explicit . When catching an exception, the object is also required to be copied. The following code will compile in earlier versions of Visual Studio, but now there will be an error:
This error can be corrected by accepting the exception by reference:
catch(D& d) { }
Strings and Macros The compiler now supports user-defined literals (user defined literals - UDL). As a consequence of this, strings (or more precisely string literals), followed by a macro without a space, are interpreted as UDL, which may cause an error or an unexpected result. For example, before it was compiled without problems:
#define _x "there" char* func() { return "hello"_x; } int main() { char * p = func(); return 0; }
The compiler interpreted the value returned by the func function as the string "hello", and the macro that was expanded to "there" and then combined the two literals into one. Now the compiler interprets this as a UDL, but since it cannot find the definition of _x among the UDLs known to it, it gives an error: error C3688: invalid literal suffix '_x'; literal operator or literal operator template 'operator ""_x' not found note: Did you forget a space between the string literal and the prefix of the following string literal? To solve this problem, you need to put a space between the line and the macro.
Rows next to each other Just as in the previous case, due to changes in the parsing of lines, building string literals that are not separated by a space, were previously interpreted as one line, but now you need to add a space to correctly compile:
char * str = "abc""def";
Just add a space between the lines:
char * str = "abc""def";
Hosting new and delete To comply with the standard C ++ 14, the behavior of the delete operator has been changed. Details can be found in C ++ Sized Deallocation . A form of the global operator delete been added, which takes the size of the object. The importance of this change is that if your code contains a delete with the same signature (corresponding to the placing operator new ), you will receive a compilation error (C2956, which points to a string using the new operator, because it is in this place that the compiler tries to determine appropriate operator delete ). The function void operator delete(void*, size_t) was the delete operator, corresponding to the function of the location operator new - void* operator new(size_t, size_t) from C ++ 11. In the new C ++ 14 standard, this delete become a normal function of allocation (that is, a global delete operator). The standard requires the following: if the host new searches for the corresponding delete and finds a standard function, the program will not compile. For example, suppose your code defines a host for new and delete :
The problem here is the following: the coincidence of the description of the operator placing the delete and the description of the new global operator. In order to avoid such a match, you can use a type other than size_t when describing the size in the new and delete positioning operators. Here you need to take into account that size_t depends on the compiler, in Visual C ++ it is an alias for unsigned int. A good solution here is to use the enumeration:
enumclassmy_type :size_t {};
Then, we need to change the declarations of the posting operators new and delete so that they use my_type as the second parameter instead of size_t. You will also need to correct the transfer of the argument to the call to new (for example, using static_cast<my_type> to perform a conversion from an integer value to an enumeration) and change the definition of the host operators by performing conversions from an enum to an integer type. In addition to the enumeration, you can use, for example, a class that has a field of type size_t. Alternatively, you can remove the posting new . If your code uses placing new to implement a pool and the passed size is the size of the object to be placed or deleted, in this case, the new delete operator may well be suitable for deleting this pool. If you do not want to change the behavior of these operators in your code right now, you can still use the / Zc: sizedDealloc- flag, which will return the old behavior. That is, a two-argument delete function will not be created, and thus there will be no conflict with the specific delete function you have.
Fields of unions (union data members) Now links can not be a union field (union). Previously, this code was compiled, now - no:
union U1 { constint i; }; union U2 { int &i; }; union U3 { struct {int &i;}; };
Now the following errors occur: test.cpp(67): error C2625: 'U2::i': illegal union member; type 'int &' is reference type
test.cpp(70): error C2625: 'U3::i': illegal union member; type 'int &' is reference type
To resolve this problem, you need to change the reference to the pointer or just the usual value. Changing the type to a pointer will require changes in the code that accesses this field. Changing the type to value will change the value in the union, which will affect other fields of the union. Also in this case the size of the union may change.
Unnamed unification Unnamed unions have become more standard. Previously, an explicit constructor and destructor were generated for nameless unions. They are now declared removed.
structS { S(); }; union { struct { S s; }; } u; // C2280
The following errors are generated in Visual Studio 2015 Preview: error C2280: '<unnamed-type-u>::<unnamed-type-u>(void)': attempting to reference a deleted function
note: compiler has generated '<unnamed-type-u>::<unnamed-type-u>' here
To solve this problem, you need to define your constructor and / or destructor.
structS {// , S() {} }; union { struct { S s; }; } u;
Associations with anonymous structures In order to ensure compliance with the standard, the run-time behavior for members of anonymous structures in associations was changed. The constructor of anonymous structures — members of associations — is no longer invoked implicitly when a union is created. Also, the destructor of such fields is not invoked implicitly when the union exits from the visibility block. Example:
#include<stdio.h> struct S { S() { printf("Creating S\n"); } ~S(){ printf("Destroying S\n"); } }; union U { struct { S s; }; U() {} ~U(){} }; void f() { U u; // } int main() { f(); char s[1024]; printf("Press any key.\n"); gets_s(s); return 0; }
Previously, both the constructor and the destructor were called. Now they are not called. The compiler issues warnings: warning C4587: 'U::s': behavior change: constructor is no longer implicitly called
warning C4588: 'U::s': behavior change: destructor is no longer implicitly called
To restore the old behavior you need to give the name an anonymous structure. The run-time behavior of non-anonymous structures remains independent of the compiler version.
#include<stdio.h> struct S { S() { printf("Creating S.\n"); } ~S() { printf("Destroying S\n"); } }; union U { struct { S s; } namedStruct; U() {} ~U() {} }; void f() { U u; } int main() { f(); char s[1024]; printf("Press any key.\n"); gets_s(s); return 0; }
Alternatively, you can try to transfer the code of the constructor and the destructor structure to new methods and call them from the constructor and destructor of the union:
#include<stdio.h> struct S { void Create() { printf("Creating S.\n"); } void Destroy() { printf("Destroying S\n"); } }; union U { struct { S s; }; U() { s.Create(); } ~U() { s.Destroy(); } }; void f() { U u; } int main() { f(); char s[1024]; printf("Press any key.\n"); gets_s(s); return 0; }
Template resolution Name resolution for templates has also been changed. In C ++, when considering candidates when resolving names, it is quite possible that one or more names may be invalid instantiations of the template. These incorrect implementations usually do not cause compilation errors (because the principle known as SFINAE is used).
Now, if SFINAE requires the compiler to specify a class template, any errors during the execution of this instantiation will be considered compiler errors. Previously, these errors were ignored. For example:
#include<type_traits> template<typename T> struct S { S() = default; S(const S&); S(S&&); template<typename U, typename = typename std::enable_if<std::is_base_of<T, U>::value>::type> S(S<U>&&); }; struct D; void f1() { S<D> s1; S<D> s2(s1); } struct B { }; struct D : public B { }; void f2() { S<D> s1; S<D> s2(s1); }
The new compiler will display the following error message: type_traits(1110): error C2139: 'D': an undefined class is not allowed as an argument to compiler intrinsic type trait '__is_base_of'
..\t331.cpp(14): note: see declaration of 'D'
..\t331.cpp(10): note: see reference to class template instantiation 'std::is_base_of<T,U>' being compiled
with
[
T = d,
U = D
]
The reason for the error is that in the place of the first is_base_of call is_base_of class D has not yet been defined. In this case, the correction of the error will be as follows: you do not need to use such type checks before defining the classes, then you need to transfer the definition of B and D d to the beginning of the file. If these definitions are in header files, you need to check the order of inclusion to ensure that class definitions are included before the problem pattern is used.
Copy Constructors In both Visual Studio 2013 and Visual Studio 2015 RC, the compiler creates a copy constructor for a class if the class has a user-defined motion constructor, but no user-defined copy constructor. In Dev14, this implicitly generated copy constructor is marked as "= delete".
Changes in the C Runtime Library (CRT)
General changes
Refactoring binary files The CRT library was divided into two binary files — the CRT shared library (Universal CRT - ucrtbase), which contains most of the standard functionality, and the VC Runtime library (vcruntime140), which contains compiler-dependent functionality (for example, exception handling and built-in functions ( intrinsics)). If you use the standard settings of the project, then this change will not affect you in any way, since the linker will begin to use these new libraries. If you set the Ignore All Default Libraries project's linker property to Yes , or you used the linker flag / NODEFAULTLIB, then you should update your list of libraries (the project property Additional Dependencies ), that is, include the new libraries yourself. Or rather, replace the old CRT libraries (libcmt.lib, libcmtd.lib, msvcrt.lib, msvcrtd.lib) with new equivalents. For each of the two new libraries, there is a static (.lib) and dynamic (.dll) version, as well as a release build (without a suffix) and a debug build (with the suffix "d"). More details here: CRT Library Features
<locale.h>
localeconv The localeconv function declared in locale.h now works correctly when the stream locale is enabled ( per-thread locale ). Previously, this function returned Iconv to a global, rather than streaming, locale. If you are using a stream locale, you should check how the new behavior of localeconv will affect your program.
<math.h>
C ++ library functions overload Previously, <math.h> overloaded some, but not all, math library functions. An . , <math.h> . <math.h>.
new and delete In the previous version of the library, the implementation-dependent new and delete operators were exported from a dynamic library (for example, msvcr120.dll). These operators are now always linked statically with your binaries, even if dynamic libraries are used. This is not a very significant change for native or mixed code (/ clr), but if your code is compiled with the / clr: pure flag, then after updating the code may stop compiling. In this case, you need to make sure that the header files <new.h> . : /clr:pure . connected in all the right places <new.h> . : /clr:pure . <new.h> . : /clr:pure .