Visual C ++ Changes

Original author: msdn.microsoft.com
  • Transfer
When you want to update the version of the Visual C ++ compiler (for example, switch from Visual Studio from 2013 to 2015), it will not be out of place to find out why you may encounter the fact that code that was previously successfully compiled and executed will now cause compilation errors and / or runtime errors.
These problems can be caused by numerous changes to the compiler to comply with the C ++ standard, changes in function signatures, or changes in the location of objects in memory.

In order to avoid run-time errors (they are known to be the most difficult to find), we recommend that you never make a static link to binary files received 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 binaries (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 writing code that depends on the specific location of objects in memory (unless it is a COM interface or a POD object). If you now have this 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 to 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 to the compiler
- Changes to the C Runtime Library (CRT)
- Changes to STL
- Changes to MFC and ATL

Compiler Changes


  • / Zc: forScope - The compiler flag is /Zc:forScope-deprecated and will be removed in the future. Now, when using this flag, the compiler will throw a warning D9035.
    This flag is used to use the non-standard C ++ extension - the use of variables declared in the loop description foroutside this loop. This flag is necessary only if another flag is set - /Za( conform to the standard ), because without /Za, the use of variables from the loop description is enabled by default. If you do not need to worry about cross-platform (for example, it is not supposed to collect code by other compilers), you can turn off the flag/Za(set the project property “Disable Language Extensions” to “No”). If you care about cross-platform and compliance with the standard, then you need to rewrite such sections of code 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 compiler flag /Zg( prototyping functions ) is no longer available for use (it previously had the deprecated attribute)

  • Now you can not 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 use 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 constor static. Example:
    struct S {
        mutable int &r;
    };
    

    This used to compile, now the compiler will throw error C2071. To fix, you just need to remove mutable.

  • char_16_t and char_32_t
    Now you cannot use char_16_t and char_32_t as aliases of 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 
    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 this, you need to remove the declaration of aliases and rename any other identifiers that conflict with the newly entered ones.

  • Non-type (non-type) template parameters
    Code that includes non-type template parameters is now correctly checked for type compatibility. For example, the following code used to compile without errors:
    struct S1
    {
        void f(int);
        void f(int, int);
    };
    struct S2
    {
        template  void f() {}
    };
    void f()
    {
         S2 s2;
         s2.f();
    }
    

    Now the compiler will throw an error, because 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). To get rid of this error, make sure that the type of the template argument matches the type of the parameter.
    error C2893: Failed to specialize function template 'void S2::f(void)'
    note: With the following template arguments:
    note: 'C=S1'
    note: 'Function=S1::f'



  • __declspec (align)
    The compiler no longer accepts __declspec(align)for functions. In truth, he never accepted, but now he will give out error C3323. To get rid of it, simply remove this expression from the function declaration. Since this had no effect before, it will not change anything in your program.

  • Exception Handling
    Several changes have occurred in exception handling. First, exception objects must be copyable and moveable. Previously, similar code was compiled, now there will be an error:
    struct S {
    public:
        S();
    private:
        S(const S &);
    };
    int main()
    {
        throw S(); // error
    }
    

    The problem here is that the copy constructor is declared private, so the object cannot be copied, which is usually required when handling the exception. The same applies when the constructor is declared explicit.
    struct S {
        S();
        explicit S(const S &);
    };
    int main()
    {
        throw S(); // error
    }
    

    To get rid of this problem, make sure that the constructor for the exception object is declared in the public zone and explicit.
    When catching an exception, the object is also required to be copied. The following code compiles in earlier versions of Visual Studio, but now there will be an error:
    struct B {
    public:
        B();
    private:
        B(const B &);
    };
    struct D : public B {
    };
    int main()
    {
        try
        {
        }
        catch (D d) // error
        {
        }
    }
    

    This error can be fixed by accepting the exception at the link:
    catch(D& d)
    {
    }
    

  • Lines and macros
    The compiler now supports user defined literals (UDLs). As a result of this, strings (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, earlier this 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 expanded into "there" and then joined the two literals into one. Now the compiler interprets this as 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.

  • Lines located side by side
    As in the previous case, due to changes in parsing strings, building string literals next to each other that does not share a space were previously interpreted as a single line, but now for correct compilation you need to add a space:
    char * str = "abc""def";
    

    Just add a space between the lines:
    char * str = "abc" "def";
    

  • Hosting new and delete
    To comply with the C ++ 14 standard, the behavior of the operator has been changed delete. Details can be found in C ++ Sized Deallocation . A form of a global operator has been added deletethat takes the size of an object. The importance of this change is that if your code has an operator deletewith the same signature (corresponding to the host operator new), you will get a compilation error (C2956, which points to a string using the operator new, since the compiler tries to determine the suitable operator in this place delete) .
    The function void operator delete(void*, size_t)was the host operator delete, corresponding to the host operator function new- void* operator new(size_t, size_t)from C ++ 11. In the new C ++ 14 standard, thisdeletebecame a regular deallocation function (i.e. a global operator delete). The standard requires the following - if the host is newlooking for the appropriate one deleteand finds a standard function, the program will not compile.
    For example, suppose your code defines the host newand delete:
    void * operator new(std::size_t, std::size_t);
    void operator delete(void*, std::size_t) noexcept; 
    

    The problem here is this: matching the description of the host operator deleteand the description of the new global operator. In order to avoid such a coincidence, you can use a type other than size_t when describing the size in the placement operators newand delete. 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 would be to use an enumeration:
    enum class my_type : size_t {};
    

    Then, you need to change the ad is running operator newand deleteso that the second parameter instead of size_t they took my_type. It will also be necessary to correct the transfer of the argument to the call new(for example, using a conversion from an integer value to an enumeration) and change the definition of the placement operators, making the conversion from an enumeration to an integer type. In addition to listing, you can use, for example, a class that has a field of type size_t. As an alternative solution, you can remove the host . If your code uses the allocation and transfer size of the pool, this is the size of the object to place or delete, in which case a new statementstatic_cast
    newnewdeletemay well be suitable for removing this pool.
    If you do not want to change the behavior of these operators in your code right now, you can use the / Zc: sizedDealloc- flag for now, 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 delete function you define.

  • Fields of associations (union data members)
    Now links cannot be a field of union (union). This code used to compile, now it doesn't:
    union U1 {
        const int i;
    };
    union U2 {
       int &i;
    };
    union U3 {
        struct {int &i;};
    };
    

    Now the following errors occur: To resolve this problem, you need to change the pointer reference or just a regular value. Changing the type to a pointer will require changes to the code that accesses this field. Changing the type to a value will allow changing the value in the union, which will affect other fields of the union. Also in this case, the size of the union may change.
    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



  • Anonymous unions Anonymous unions
    are more in line with the standard. Previously, an explicit constructor and destructor were generated for nameless associations. Now they are declared deleted.
    struct S {
      S();
     };
     union {
      struct {
       S s;
      };
     } u; // C2280
    

    The following errors are generated in Visual Studio 2015 Preview: To solve this problem, you need to define your constructor and / or destructor
    error C2280: '::(void)': attempting to reference a deleted function

    note: compiler has generated '::' here


    struct S {
         // Определяем конструктор по умолчанию, добавляя пустое тело
        S() {} 
    };
    union {
        struct {
        S s;
        };
    } u;
    

  • Associations with anonymous structures
    In order to ensure compliance with the standard, runtime behavior for members of anonymous structures in associations has been changed. The constructor of anonymous structures - members of associations - is no longer implicitly called when creating an association. Also, the destructor of such fields is not called implicitly when the union exits from the visibility block. Example:
    #include 
    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: To restore old behavior, you need to give a name to the anonymous structure. The runtime behavior of non-anonymous structures remains independent of the compiler version.
    warning C4587: 'U::s': behavior change: constructor is no longer implicitly called

    warning C4588: 'U::s': behavior change: destructor is no longer implicitly called


    #include 
    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;
    }
    

    As an alternative solution, you can try to transfer the constructor and structure destructor code to new methods and call them from the union constructor and destructor:
    #include 
    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
    Changes have also been made to the name resolution for templates. In C ++, when considering candidates for name resolution, it is quite possible that one or more of the names may be invalid instantiations of the template. These incorrect implementations usually do not cause compilation errors (since the principle known as SFINAE is used).

    Now, if SFINAE requires the compiler to instantiate a class template, any errors during this instantiation will be considered compiler errors. Previously, these errors were ignored. For instance:
    #include 
    template
    struct S
    {
        S() = default;
        S(const S&);
        S(S&&);
        template::value>::type>
        S(S&&);
    };
    struct D;
    void f1()
    {
        S s1;
        S s2(s1);
    }
    struct B
    {
    };
    struct D : public B
    {
    };
    void f2()
    {
        S s1;
        S s2(s1);
    }
    

    The new compiler will generate 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' being compiled

    with
    [
        T = D
        U = D
    ]
    

    The reason for the error is that at the place of the first call, is_base_ofclass D is not yet defined.
    In this case, the error correction will be as follows: you do not need to use such type checks before defining classes, so you need to transfer the definition of B and D d to the beginning of the file. If these definitions are in the header files, you need to check the inclusion order to make sure that class definitions are included before the problematic template is used.

  • Copy constructors
    In both Visual Studio 2013 and Visual Studio 2015 RC, the compiler creates a copy constructor for a class if this class has a user-defined move constructor but no user-defined copy constructor. In Dev14, this implicitly generated copy constructor is marked as "= delete".


Changes to the C Runtime Library (CRT)


General changes


  • Refactoring binary files
    The CRT library was divided into two binary files - the common CRT 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 project settings, then this change will not affect you in any way, since the linker will begin to use these new libraries. If you set the project linker property of Ignore All Default Libraries to Yes , or you used the / NODEFAULTLIB linker flag, then you should update your list of libraries (project property Additional Dependencies), that is, include new libraries in it 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) versions, as well as a release build (without a suffix) and a debug build (with a suffix “d”). More details here: CRT Library Features


  • localeconv
    function localeconv , announced in locale.h now works correctly when streaming locale (included The per-thread locale ). Earlier this function returned Iconv global, but not streaming, locales.
    If you use a streaming locale, you should check how the new localeconv behavior will affect your program.


  • C ++ library function overloading
    Previously, some, but not all, mathematical library functions were overloaded. IN была определена перегрузка остальных функций. Это вело к проблемам разрешения перегрузки, если включен только . Теперь все перегрузки перенесены из в .


    Приведение в соответствие стандарту чисел с плавающей точкой
    В математической библиотеке было сделано много изменений для приближения к соответствию стандарту IEEE-754 и Приложению F стандарта C11, основное внимание было уделено особым случаям (NaN и бесконечности). Например, при передаче в функцию библиотеки NaN раньше часто возникала ошибка, сейчас - не возникает. Более подробно узнать об этом можно здесь: IEEE 754 Standard, Annex F of the C11 Standard.
    Эти изменения не вызовут ошибок времени компиляции, однако программа может начать вести себя по другому - более соответственно стандартам.


    FLT_ROUNDS
    Раньше этот макрос разворачивался в константное выражение, что было неправильно, так как способ округления числа мог измениться во время выполнения программы (например, с помощью fesetround). Сейчас FLT_ROUNDS это учитывает.


     and 


    • new and delete
      In the previous version of the library, implementation-dependent operators new and delete were exported from a dynamic library (eg msvcr120.dll). These operators now always link 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 header files are connected in all the right places. или . Еще нужно учесть следующее: флаг /clr:pure объявлен устаревшим и будет удален в одном из следующих релизов.


Also popular now: