Visual Studio 2017 を使用することをお勧めします

Visual C++ 2015 での互換性に影響する変更点

 

公開日: 2016年7月

Visual Studio 2017 RC の最新のドキュメントの詳細については、Visual Studio 2017 RC ドキュメントをご参照ください。

Visual C++ コンパイラの新しいバージョンにアップグレードすると、以前にコンパイルと動作が正常に行えたコードでコンパイルやランタイム エラーが発生する場合があります。 新しいバージョンでこのような問題を引き起こす変更は互換性に影響する変更と呼ばれ、通常は C++ 言語の基準、関数シグネチャ、またはメモリ オブジェクトのレイアウトの変更によって必要となります。

検出や診断が難しいランタイム エラーを回避するには、異なるバージョンのコンパイラを使用してコンパイルされたバイナリには静的にリンクしないことをお勧めします。 また、EXE または DLL プロジェクトをアップグレードする場合、リンクするライブラリもアップグレードします。 CRT (C Runtime) または STL (Standard Template Library) 型を使用している場合は、異なるバージョンのコンパイラを使用してコンパイルされたバイナリ間 (DLL を含む) で渡さないでください。 詳細については、「DLL の境界を越えて CRT オブジェクトを渡す場合に発生する可能性のあるエラー」を参照してください。

さらに、COM インターフェイスまたは POD オブジェクトではないオブジェクトで、特定のレイアウトに依存するコードを記述しないことをお勧めします。 このようなコードを記述している場合、アップグレード後に動作することを確認する必要があります。 詳細については、「ABI の境界での移植性」を参照してください。

ここからは、Visual Studio 2015 の Visual C++ の特定の互換性に影響する変更点について説明します。この記事における「新しい動作」または「現在」という語は、そのバージョンを指します。 「従来の動作」や「以前」という語は、Visual Studio 2013 以前のリリースを指します。 Visual Studio 2015 Update 1 での追加の変更については、「Update 1 での互換性に影響する変更点」をご覧ください。

  1. コンパイラの互換性に影響する変更点

  2. C ランタイム (CRT) ライブラリの互換性に影響する変更点

  3. 標準の C++、および標準テンプレート ライブラリ (STL) の互換性に影響する変更点

  4. MFC と ATL の互換性に影響する変更点

  5. 同時実行ランタイムの互換性に影響する変更点

  • /Zc:forScope - オプション

    コンパイラ オプション /Zc:forScope- は使用できなくなりました。今後のリリースからは削除されます。

    Command line warning  D9035: option 'Zc:forScope-' has been deprecated and will be removed in a future release  
    
    

    このオプションは通常、標準ではスコープから外れるポイントの後のループ変数を使用する、非標準のコードを許可するために使用されていました。 これは /Za オプションを使ってコンパイルするときにのみ必要でした。/Za がない場合は、ループの後でも常に for ループ変数が使用できるからです。 標準への準拠を考慮しない場合 (たとえば、コードを他のコンパイラに移植しない場合)、/Za オプションをオフにする (または、[言語拡張機能の無効化] プロパティを [いいえ] に設定する) こともできます。 移植可能で標準に準拠したコードの記述を考慮する場合、標準に準拠するようコードを再記述する必要があります。そのためには、変数の宣言をループの外側に移動します。

    // zc_forScope.cpp // compile with: /Zc:forScope- /Za // C2065 expected int main() { // Uncomment the following line to resolve. // int i; for (int i =0; i < 1; i++) ; i = 20;   // i has already gone out of scope under /Za }  
    
    
  • /Zg コンパイラ オプション

    /Zg コンパイラ オプション (関数プロトタイプの生成) は使用できなくなりました。 前バージョンで、このコンパイラ オプションは使用できなくなりました。

  • mstest.exe のコマンド ラインから C++/CLI で単体テストを実行できなくなりました。 代わりに、vstest.console.exe を使用します。 「VSTest.Console.exe のコマンド ライン オプション」を参照してください。

  • mutable キーワード

    mutable ストレージ クラス指定子は、エラーなしで以前コンパイルされていた場所で使用できなくなりました。 現在、コンパイラによってエラー C2071 (無効なストレージ クラス) が出されます。 標準では、変更可能な指定子はクラスのデータ メンバーの名前にのみ適用でき、const または static として宣言された名前には適用できません。また、参照メンバーにも適用できません。

    次に例を示します。

    struct S { mutable int &r; };  
    
    

    以前のバージョンの Visual C++ コンパイラはこれを受け入れていましたが、現在のコンパイラでは次のエラーが出されます。

    エラー C2071: 'S::r': ストレージ クラスが正しくありません  
    
    

    エラーを修正するには、単に冗長の変更可能なキーワードを削除します。

  • char_16_t と char32_t

    char16_t または char32_t を typedef の別名として使用できなくなりました。これらの型は現在、組み込みとして扱われているからです。 ユーザーとライブラリの作成者が char16_t と char32_t をそれぞれ、uint16_t、uint32_t の別名として定義することが一般的でした。

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

    コードを更新するには、typedef 宣言を削除してこれらの名前と競合するその他の ID の名前を変更します。

  • 非型テンプレート パラメーター

    非型テンプレート パラメーターを含む特定のコードは現在、明示的なテンプレート引数を指定すると、型の互換性について正しくチェックされます。 たとえば、次のコードは、以前のバージョンの Visual C++ でエラーなしでコンパイルしたものです。

    struct S1 { void f(int); void f(int, int); }; struct S2 { template <class C, void (C::*Function)(int) const> void f() {} }; void f() { S2 s2; s2.f<S1, &S1::f>(); }  
    
    
    

    現在のコンパイラは、正しくエラーを出します。テンプレート パラメーターの型がテンプレートの引数と一致しないからです (パラメーターは const メンバーへのポインターですが、関数 f は非 const です)。

    エラー C2893: 関数テンプレート 'void S2::f(void)' の特定に失敗しました注: 次のテンプレート引数で: 注: 'C=S1' 注: 'Function=S1::f'  
    
    

    コードのこのエラーに対処するには、使用するテンプレート引数の型が、テンプレート パラメーターの宣言された型と一致することを確認してください。

  • __declspec(align)

    コンパイラは関数で __declspec(align) を受け入れなくなりました。 これは常に無視されていましたが、コンパイラ エラーを生成するようになりました。

    error C3323: 'alignas' and '__declspec(align)' are not allowed on function declarations  
    
    

    この問題を修正するには、関数の宣言から __declspec(align) を削除してください。 これは影響がなかったため、削除しても何も変わりません。

  • 例外処理

    例外処理への変更がいくつかあります。 まず、例外オブジェクトはコピー可能または移動可能にする必要があります。 次のコードは Visual Studio 2013 の Visual C++ ではコンパイルされますが、Visual Studio 2015 の Visual C++ ではコンパイルされません。

    struct S { public: S(); private: S(const S &); }; int main() { throw S(); // error }  
    
    
    

    問題は、コピー コンストラクターはプライベートであるために通常の例外処理とは異なりオブジェクトをコピーできないことです。 コピー コンストラクターが explicit として宣言されている場合も同じことが当てはまります。

    struct S { S(); explicit S(const S &); }; int main() { throw S(); // error }  
    
    
    

    コードを更新するには、例外オブジェクトのコピー コンストラクターがパブリックであり、explicit とマークされていないことを確認します。

    値によって例外をキャッチする場合も、例外オブジェクトをコピー可能にする必要があります。 次のコードは Visual Studio 2013 の Visual C++ ではコンパイルされますが、Visual Studio 2015 の Visual C++ ではコンパイルされません。

    struct B { public: B(); private: B(const B &); }; struct D : public B { }; int main() { try { } catch (D d) // error { } }  
    
    
    

    この問題を解決するには、catch のパラメーターの型を参照に変更します。

    catch(D& d) { }  
    
    
  • マクロに続く文字列リテラル

    このバージョンでは、コンパイラはユーザー定義リテラルをサポートするようになりました。 その結果、空白文字の介入がないマクロに続く文字列リテラルはユーザー定義のリテラルとして解釈されます。これにより、エラーまたは予期しない結果が起こる可能性があります。 たとえば、以前のコンパイラでは次のコードが正常にコンパイルされていました。

    #define _x "there" char* func() { return "hello"_x; } int main() { char * p = func(); return 0; }  
    
    

    コンパイラはこれを、マクロに続く "hello" というリテラル文字列として解釈していました。これは "there" に拡張され、2 つの文字列リテラルが 1 つに連結されていました。Visual Studio 2015 の Visual C++ では、コンパイラはこれをユーザー定義リテラルと解釈しますが、一致するユーザー定義リテラル _x が定義されていないため、エラーになります。

    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?  
    
    
    

    この問題を解決するには、文字列リテラルとマクロの間に空白に追加します。

  • 隣接する文字列リテラル

    以前と同様、文字列の解析に関連する変更のため、空白なしの隣接する文字列リテラル (ワイド文字列リテラルまたはナロー文字列リテラルのいずれか) は、以前のバージョンの Visual C++ では、単一の連結文字列と解釈されていました。Visual Studio 2015 の Visual C++ では、2 つの文字列間に空白を追加する必要があります。 たとえば、次のコードを変更する必要があります。

    char * str = "abc""def";  
    
    

    単に 2 つの文字列間に空白を追加します。

    char * str = "abc" "def";  
    
    
  • placement new と delete

    C++14 標準に準拠させるために delete 演算子に対して変更が加えられました。 標準の変更について詳しくは、「C++ サイズの割り当て解除」をご覧ください。 変更により、size パラメーターを取るグローバルな delete 演算子のフォームが追加されます。 互換性に影響する変更は、(placement new 演算子と一致させるために) 以前同じシグネチャで delete 演算子を使用していた場合、コンパイラ エラーを受け取ります (これは C2956 というエラーで、placement new が使用されるポイントで発生します。それは、一致する適切な delete 演算子の識別をコンパイラが試行するコードの場所だからです)。

    関数 void operator delete(void *, size_t) は、C++11 の placement new 関数 "void * operator new(size_t, size_t)" に対応する placement delete 演算子でした。 現在、C++14 サイズの割り当て解除では、この delete 関数は通常の解放関数 (グローバルな delete 演算子) です。 標準では、placement new の使用で対応する delete 関数を検索し、通常の解放関数を見つけた場合、プログラムの形式が不適切である必要があります。

    たとえば、コードで placement new と placement delete の両方を定義するとします。

    void * operator new(std::size_t, std::size_t); void operator delete(void*, std::size_t) noexcept;  
    
    
    

    この問題は、定義した placement delete 演算子と新しいグローバル サイズの delete 演算子の間の関数シグネチャの一致により発生します。 placement new 演算子および delete 演算子で size_t とは異なる型を使用できるかどうかを検討してください。 size_t typedef の型はコンパイラによって異なります。これは Visual C++ の符号なし整数の typedef です。 適切なソリューションでは、次のように列挙型を使用します。

    enum class my_type : size_t {};  
    
    
    

    次に、placement new と delete の定義を変更し、size_t の代わりにこの型を 2 番目の引数として使用します。 placement new の呼び出しを更新して新しい型を渡したり (たとえば、static_cast<my_type> を使用することにより整数値から変換する)、new と delete の定義を更新して整数型にキャスト バックしたりする必要もあります。 これに対して列挙型を使用する必要はありません。size_t メンバーを持つクラス型も機能します。

    代わりの方法として、placement new を完全に除去することもできます。 コードで placement new を使用してメモリ プールを実装する場合 (placement 引数が割り振られるまたは削除されるオブジェクトのサイズである)、独自のカスタム メモリ プール コードをサイズ割り当て解除機能で置き換えるほうが良い可能性があります。配置関数を削除でき、配置関数の代わりに独自の 2 つの引数 delete 演算子だけを使用することができます。

    コードを即時に更新しない場合は、コンパイラ オプション /Zc:sizedDealloc- を使用して、従来の動作に戻すことができます。 このオプションを使用すると、2 つの引数を持つ削除関数が存在せず、placement delete 演算子との競合は発生しません。

  • 共用体データ メンバー

    共用体データ メンバーで参照型を使用することはできなくなりました。 次のコードは Visual Studio 2013 の Visual C++ で正常にコンパイルされますが、Visual Studio 2015 の Visual C++ ではエラーになります。

    union U1 { const int i; }; union U2 { int &i; }; union U3 { struct {int &i;}; };  
    
    

    上のコードを実行すると、次のエラーが生成されます。

    test.cpp(67): エラー C2625: 'U2::i': 正しくない共用体メンバーです; 型 'int &' は参照型です test.cpp(70): エラー C2625: 'U3::i': 正しくない共用体メンバーです; 型 'int &' は参照型です  
    
    

    この問題に対処するには、参照型をポインターか値に変更します。 ポインターに型を変更する場合、共用体フィールドを使用するコードでの変更が必要です。 コードを値に変更すると、共用体に格納されているデータが変更されます。これは、他のフィールドに影響を与えます。共用体型のフィールドは同じメモリを共有するからです。 値のサイズによっては、共用体のサイズも変更される場合があります。

  • 匿名共用体の標準への適合が改善されました。 以前のバージョンのコンパイラでは、匿名共用体に対して明示的なコンストラクターとデストラクターが生成されていました。 これらは Visual Studio 2015 の Visual C++ で削除されています。

    struct S { S(); }; union { struct { S s; }; } u; // C2280  
    
    

    上のコードを実行すると、Visual Studio 2015 の Visual C++ で次のエラーが生成されます。

    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  
    
    

    この問題を解決するには、コンストラクターおよび/またはデストラクターの独自の定義を提供してください。

    struct S { // Provide a default constructor by adding an empty function body. S() {} }; union { struct { S s; }; } u;  
    
    
  • 匿名構造体を持つ共用体

    標準と準拠させるために、共用体の匿名構造体メンバーのランタイムの動作が変更されました。 共用体の匿名構造体のメンバーのコンストラクターは、そのような共用体の作成時に暗黙的に呼び出されなくなりました。 また、共用体の匿名構造体のメンバーのデストラクターも、共用体がスコープから外れたときに暗黙的に呼び出されなくなりました。 次のコードを検討します。共用体 U に匿名構造体が含まれています。この匿名構造体には、名前付き構造体 S のメンバーが含まれており、その構造体にはデストラクターが含まれています。

    #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; // Destructor implicitly called here. } int main() { f(); char s[1024]; printf("Press any key.\n"); gets_s(s); return 0; }  
    
    

    Visual Studio 2013 の Visual C++ では、S のコンストラクターは共用体の作成時に呼び出され、S のデストラクターは関数 f のスタックがクリーンアップされるときに呼び出されます。 しかし、Visual Studio 2015 の Visual C++ では、コンストラクターとデストラクターは呼び出されません。 コンパイラによって、この動作の変更に関する警告が出されます。

    警告 C4587: 'U::s': 動作変更: コンストラクターは暗黙的に呼び出されなくなりました警告 C4588: 'U::s': 動作変更: デストラクターは暗黙的に呼び出されなくなりました  
    
    

    元の動作を復元するには、匿名構造体に名前を付けます。 非匿名構造体の実行時の動作は、コンパイラのバージョンに関係なく、同じです。

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

    別の方法として、新しい関数にコンストラクターとデストラクターのコードを移動し、共用体のコンストラクターおよびデストラクターからこれらの関数の呼び出しを追加します。

    #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; }  
    
    
  • テンプレートの解決

    テンプレートの名前解決に変更が加えられています。 C++ では、名前解決の候補を検討する場合、一致の可能性として検討されている 1 つ以上の名前により、無効なテンプレート インスタンス化が生成される可能性があります。 これらの無効なインスタンス化は通常、それ自体はコンパイラ エラーの原因にはなりません。これは SFINAE (Substitution Failure Is Not An Error: 置き換えの失敗はエラーではない) と呼ばれます。

    SFINAE のコンパイラがクラス テンプレートの特殊化のインスタンス化を必要とする場合は、この処理中に発生したエラーはコンパイラ エラーです。 以前のバージョンでは、コンパイラはこのようなエラーを無視していました。 次に例を示します。

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

    現在のコンパイラでコンパイルすると、次のエラーが表示されます。

    type_traits(1110): エラー C2139: 'D': 定義されていないクラスは、コンパイラの組み込み型の特徴である '__is_base_of' への引数として使用できません..\t331.cpp(14): 注: 'D' の宣言を参照..\t331.cpp(10): 注: [ T=D, U=D ] でコンパイルされるクラス テンプレートのインスタンス化 'std::is_base_of<T,U>' のリファレンスを参照  
    
    

    これは、is_base_of の最初の呼び出しの時点でクラス 'D' がまだ定義されていないためです。

    この場合の修正は、クラスが定義されるまでそのような型の特徴を使用しないことです。 B と D の定義をコード ファイルの先頭に移動すると、エラーが解決されます。 定義がヘッダー ファイルにある場合、ヘッダー ファイルの include ステートメントの順序を確認し、問題のあるテンプレートが使用される前にクラス定義がコンパイルされるようにしてください。

  • コピー コンストラクター

    Visual Studio 2013 と Visual Studio 2015 の両方において、コンパイラは、クラスにユーザー定義の移動コンストラクターがあり、ユーザー定義のコピー コンストラクターはない場合に、そのクラスのコピー コンストラクターを生成します。 Dev14 では、この暗黙的に生成されたコピー コンストラクターは "= delete" とマークされています。

一般的な変更

  • リファクタリング バイナリ

    CRT ライブラリは 2 つの異なるバイナリにリファクタリングされています。その 1 つはユニバーサル CRT (ucrtbase) で、標準機能のほとんどが含まれています。もう 1 つは VC ランタイム ライブラリ (vcruntime140) で、例外処理や組み込み関数などのコンパイラ関連の機能が含まれています。 既定のプロジェクト設定を使用している場合は、この変更によって影響を受けません。リンカーは、新しい既定のライブラリを自動的に使用するからです。 プロジェクトの [リンカー] プロパティの [すべての既定のライブラリの無視] を [はい] に設定するか、コマンドラインで /NODEFAULTLIB リンカー オプションを使用する場合、([追加の依存ファイル] プロパティの) ライブラリのリストを更新して、新しいリファクタリング ライブラリを組み込む必要があります。 古い CRT ライブラリ (libcmt.lib、libcmtd.lib、msvcrt.lib、msvcrtd.lib) をリファクタリングした同等のライブラリで置き換えます。 2 つのリファクタリング ライブラリのそれぞれについて、静的 (.lib) バージョンと動的 (.dll) バージョンがあり、リリース (サフィックスなし) バージョンとデバッグ (サフィックス "d" を持つ) バージョンがあります。 動的バージョンには、リンク先インポート ライブラリがあります。 2 つのリファクタリング ライブラリとは、ユニバーサル CRT (具体的には ucrtbase.dll または .lib、ucrtbased.dll または .lib)、と VC ランタイム ライブラリ (libvcruntime.lib、libvcruntime.dll、libvcruntimed.lib、および libvcruntimed.dll) です。 「CRT ライブラリの機能」を参照してください。

<locale.h>

  • localeconv

    現在、locale.h で宣言される localeconv 関数は、スレッドごとのロケールが有効なときに正常に機能します。 以前のバージョンのライブラリでは、この関数はスレッドのロケールではなくグローバル ロケールの lconv データを返していました。

    スレッドごとのロケールを使用する場合、localeconv の使用を確認し、返される lconv データがグローバル ロケール用であることがコードで想定されているかどうかを確認し、必要に応じて変更する必要があります。

<math.h>

  • 数値演算ライブラリ関数の C++ のオーバーロード

    以前のバージョンでは、<math.h> は、数値演算ライブラリ関数の C++ オーバーロードのいくつか (すべてではない) を定義していました。 <cmath> はそれ以外のオーバーロードを定義するため、すべてのオーバーロードを取得するには、<cmath> ヘッダーを組み込む必要がありました。 そのため、<math.h> だけしか組み込まれていないコードでは、関数のオーバーロードの解決方法に問題が生じていました。 現在は、すべての C++ オーバーロードが <math.h> から削除されており、<cmath> にのみ存在しています。

    エラーを解決するには、<math.h> から削除された関数の宣言を取得する <cmath> を組み込んでください。 移動された関数を次の表に示します。

    移動された関数:

    1. double abs(double) および float abs(float)

    2. double pow(double, int)、float pow(float, float)、float pow(float, int)、long double pow(long double, long double)、long double pow(long double, int)

    3. 次の浮動小数点関数の float バージョンおよび long double バージョン: acos、acosh、asin、asinh、atan、atanh、atan2、cbrt、ceil、copysign、cos、cosh、erf、erfc、exp、exp2、expm1、fabs、fdim、floor、fma、fmax、fmin、fmod、frexp、hypot、ilogb、ldexp、lgamma、llrint、llround、log、log10、log1p、log2、lrint、lround、modf、nearbyint、nextafter、nexttoward、remainder、remquo、rint、round、scalbln、scalbn、sin、sinh、sqrt、tan、tanh、tgamma、trunc

    math.h ヘッダーだけが組み込まれている浮動小数点型の abs を使用するコードがある場合、浮動小数点バージョンは使用できなくなります。そのため、浮動小数点引数を持つ場合でも、現バージョンでは、abs(int) の呼び出しで解決します。 これによって、次のエラーが生成されます。

    警告 C4244: 'argument' : 'float' から 'int' への変換でデータが失われる可能性があります  
    
    

    この警告の修正方法は、abs の呼び出しを、abs の浮動小数点バージョン (double 引数の場合は fabs、float 引数の場合は fabsf) で置き換えるか、cmath ヘッダーを組み込んで abs を引き続き使用するかのどちらかです。

  • 浮動小数点の準拠

    NaNs 値や無限大値などの特殊なケースの入力に関する IEEE-754 仕様および C11 Annex F 仕様に対する準拠を改善するために、多くの変更が数値演算ライブラリに対して加えられています。 たとえば、簡易な NaN 入力 (以前のバージョンのライブラリでは、多くの場合、エラーとして扱われていた) はエラーとして扱われなくなりました。IEEE 754 標準C11 標準の付録 F をご覧ください。

    これらの変更によってコンパイル時エラーが発生することはありませんが、プログラムの動作が変わる可能性はあり、標準に従ってより正確に動作するようになる可能性があります。

  • FLT_ROUNDS

    Visual Studio 2013 で FLT_ROUNDS マクロは定数式に拡張されましたが、これは正しくありませんでした。丸めモードは実行時に (たとえば、fesetround を呼び出すことにより) 構成することができるからです。 FLT_ROUNDS マクロは動的になり、現在の丸めモードを正確に反映します。

<new> と <new.h>

  • new と delete

    以前のバージョンのライブラリでは、実装定義演算子の new 関数と delete 関数は、ランタイム ライブラリ DLL (たとえば、msvcr120.dll) からエクスポートされていました。 現在、これらの演算子関数は常に (ランタイム ライブラリ DLL を使用する場合でも) 静的にバイナリにリンクされています。

    これはネイティブ コードまたは混合コード (/clr) の互換性に影響する変更点ではありませんが、/clr:pure としてコンパイルされるコードでは、これによってコードのコンパイルが失敗する可能性があります。 コードを /clr:pure としてコンパイルする場合、#include <new> または #include <new.h> を追加してこの変更によるビルド エラーを回避する必要があります。Visual Studio 2015 では /clr:pure は推奨されておらず、将来のリリースでは削除される可能性があります。

<process.h>

  • _beginthread および _beginthreadex

    現在、_beginthread 関数と _beginthreadex 関数には、モジュールへの参照が含まれています。そのモジュールで、スレッドの期間に関するスレッド プロシージャが定義されています。 これは、スレッドの実行が完了するまでモジュールがアンロードされないようにする上で役立ちます。

<stdarg.h>

  • va_start と参照型

    現在、va_start は C++ コードをコンパイルするときに、渡される引数が参照型でないことをコンパイル時に検証します。 参照型の引数は、C++ 標準では禁止されています。

<stdio.h> と <conio.h>

  • 現在、関数の printf ファミリと scanf ファミリは、インラインで定義されています。

    printf 関数と scanf 関数すべての定義は、<stdio.h>、<conio.h>、およびその他の CRT ヘッダーにインラインで移動されました。 これは、プログラムで適切な CRT ヘッダーを組み込まずにこれらの関数をローカルで宣言した場合にリンカー エラー (LNK2019、外部シンボルは未解決です) につながる互換性に影響する変更点です。 可能な場合、CRT ヘッダーが組み込まれるよう (つまり、#include <stdio.h> を追加するよう) またインライン関数が組み込まれるようコードを更新してください。これらのヘッダー ファイルが組み込まれるようコードを変更しない場合、別の方法として、付加的なライブラリをリンカー入力 legacy_stdio_definitions.lib に追加することもできます。

    このライブラリを IDE のリンカー入力に追加するには、プロジェクト ノードのコンテキスト メニューを開き、[プロパティ] を選択し、[プロジェクトのプロパティ] ダイアログ ボックスで [リンカー] を選択し、[リンカー入力] を編集して legacy_stdio_definitions.lib をセミコロン区切りリストに追加します。

    プロジェクトが、2015 より前のリリースの Visual C++ でコンパイルされた静的ライブラリとリンクする場合、リンカーによって、未解決の外部シンボルが報告される可能性があります。 これらのエラーは、_iob、_iob_func、または _imp_* 形式の特定の stdio 関数の関連インポートの内部 stdio 定義を参照する可能性があります。 Microsoft は、プロジェクトをアップグレードするときに、最新バージョンの Visual C++ コンパイラおよびライブラリですべての静的ライブラリを再コンパイルすることを推奨しています。 ライブラリが、ソースを使用できないサード パーティ ライブラリである場合、更新されたバイナリをサード パーティから要求するか、そのライブラリの使用を、古いバージョンの Visual C++ コンパイラおよびライブラリでコンパイルする別個の DLL にカプセル化する必要があります。

    System_CAPS_ICON_warning.jpg 警告

    Windows SDK 8.1 以前とリンクする場合、これらの未解決外部シンボル エラーが発生する可能性があります。 その場合、前述のように、legacy_stdio_definitions.lib をリンカー入力に追加することにより、エラーを解決する必要があります。

    未解決シンボル エラーのトラブルシューティングを実行するには、dumpbin.exe を使用して、バイナリで定義されているシンボルを調べることができます。 次のコマンド ラインを試行して、ライブラリで定義されているシンボルを表示してください。

    dumpbin.exe /LINKERMEMBER somelibrary.lib  
    
    
  • gets および _getws

    gets 関数と _getws 関数が削除されました。 gets 関数は、安全に使用できないため、C11 の標準ライブラリから削除されました。 _getws 関数は、gets に相当する Microsoft 拡張です (ただしワイド文字列)。 これらの関数の代わりとして、fgetsfgetwsgets_s、および _getws_s の使用を検討してください。

  • _cgets および _cgetws

    _cgets 関数および _cgetws 関数は削除されました。 これらの関数の代わりに、_cgets_s および _cgetws_s の使用を検討してください。

  • 無限大および NaN の書式設定

    以前のバージョンでは、無限大および NaNs は、Visual C++ 固有の sentinel 文字列のセットを使用して書式設定されていました。

    • 無限大: 1.#INF

    • 簡易な NaN: 1.#QNAN

    • シグナリング NaN: 1.#SNAN

    • 無限大 NaN: 1.#IND

    これらにはすべて、プレフィックスとして符号が付けられていた可能性があります。また、書式設定はフィールドの幅と精度に応じて若干異なる可能性があります (まれな例として、printf("%.2f\n", INFINITY) は 1.#J と出力されます。これは、#INF が 2 桁の精度に「丸められる」ためです)。 C99 で、無限大と NaNs の書式設定の方法に関して新たな要件が導入されました。 現在、Visual C++ の実装は、これらの要件に準拠しています。 新しい文字列は、次のとおりです。

    • 無限台: inf

    • 簡易な NaN: nan

    • シグナリング NaN: nan(snan)

    • 無限大 NaN:nan(ind)

    これらにはすべて、プレフィックスとして符号が付けられます。 大文字の書式指定子が使用される場合 (%f ではなく %F)、文字列は大文字で出力されます (inf ではなく INF)。これは必須です。

    scanf 関数はこれらの新しい文字列を解析するよう変更され、これらの文字列は、printf および scanf によってラウンド トリップされます。

  • 浮動小数点の書式設定と解析

    新しい浮動小数点の書式設定と解析のアルゴリズムが導入され、正確性が向上しました。 この変更は、関数ファミリ printfscanfstrtod などの関数に影響を与えます。

    従来の書式設定アルゴリズムでは、限られた桁数のみを生成し、残りの小数点以下表示桁数はゼロで埋められていました。 通常は、元の浮動小数点の値にラウンドトリップする文字列を生成するのにこれで十分ですが、正確な値 (またはそれに最も近い 10 進表現) が必要な場合は十分ではありません。 新しい書式設定アルゴリズムでは、値を表す (または指定された有効桁数を埋める) ために必要な桁数が生成されます。 改善の一例として、大きな 2 の冪の出力結果をご覧ください。

    printf("%.0f\n", pow(2.0, 80))  
    
    
    
        旧:  1208925819614629200000000    新:  1208925819614629174706176  
    
    

    従来の解析アルゴリズムでは、入力文字列の最大 17 桁の有効桁数のみが考慮され、残りの桁は破棄されていました。 文字列によって表される値に非常に近い概算値を生成するにはこれで十分であり、結果は通常、正しく丸められた結果に非常に近い値になっていました。 新しい実装では、存在するすべての桁数を考慮に入れ、すべての入力を正しく丸めた結果が生成されます (最大長 768 桁)。 加えて、現在、これらの関数は丸めモードを採用しています (fesetround によって制御可能)。 これらの関数は異なる結果を出力する可能性があるため、これは互換性に影響する潜在的な動作の変更点になります。 新しい結果は常に、古い結果より正しくなります。

  • 16 進数および無限大/NaN 浮動小数点の解析

    前述のとおり、現在、浮動小数点の解析アルゴリズムは、16 進数の浮動小数点文字列 (%a および %A printf 書式指定子によって生成されるものなど) および printf 関数によって生成されるすべての無限大および NaN 文字列を解析します。

  • %A および %a のゼロ パディング

    %a および %A 書式指定子は、浮動小数点の数値を、16 進数の仮数部およびバイナリの指数として書式設定します。 以前のバージョンでは、printf 関数は文字列をゼロで埋め込んでいましたが、それは正しくありませんでした。 たとえば、printf("%07.0a\n", 1.0) は 00x1p+0 と出力されますが、本来、print 0x01p+0 と出力されるべきです。 これは修正されました。

  • %A と %a の有効桁数

    %A と %a の書式指定子の既定の有効桁数は、以前のバージョンのライブラリでは 6 桁でした。 現在、既定の有効桁数は、C 標準に準拠して 13 桁です。

    これは、%A または %a を持つ書式文字列を使用する関数の出力におけるランタイム動作の変更です。 従来の動作では、%A 指定子を使用する出力は "1.1A2B3Cp+111" でした。 現在、同じ値の出力は "1.1A2B3C4D5E6F7p+111" です。 従来の動作を取得するには、有効桁数を指定します (たとえば %.6A)。 「精度指定」を参照してください。

  • %F 指定子

    現在、%F 書式/変換指定子がサポートされています。 無限大と NaNs が大文字で書式設定される点を除き、機能的には %f 書式指定子と同等です。

    以前のバージョンでは、実装で F と N を長さの修飾子として使用していました。 この動作は、アドレス空間がセグメント化されていた時代に由来するもので、これらの長さ修飾子は、遠近ポインター (それぞれ %Fp、%Ns) を示すために使用されていました。 この動作は削除されました。 現在、%F を検出した場合、%F 書式指定子として扱われます。%N を検出した場合、無効なパラメーターとして扱われます。

  • 指数の書式設定

    %e および %E 書式指定子は、浮動小数点の数値を、10 進数の仮数部および指数として書式設定します。 場合によっては、%g および %G 書式指定子もこの形式で数値を書式設定します。 以前のバージョンでは、CRT は 3 桁の指数部を持つ文字列を常に生成していました。 たとえば、printf("%e\n", 1.0) は 1.000000e+000 を出力していました。 これは正しくありませんでした。C では、指数部を 1 桁または 2 桁のみを使って表すことができる場合、2 桁のみを出力する必要があります。

    Visual Studio 2005 では、グローバル準拠スイッチ _set_output_format が追加されました。 プログラムは、この関数を引数 _TWO_DIGIT_EXPONENT を使って呼び出し、指数部出力の準拠を有効にすることができました。 既定の動作が変更され、標準に準拠する指数印刷モードに変更なりました。

  • 書式文字列の検証

    以前のバージョンでは、printf 関数と scanf 関数が、多くの無効な書式文字列を自動的に受け入れていました。ただし、ときどき普通でない影響が生じていました。 たとえば、%hlhlhld は %d として扱われていました。 現在、無効な書式文字列はすべて、無効なパラメーターとして扱われます。

  • fopen モードの文字列の検証

    以前のバージョンでは、fopen 関数ファミリは、正しくない一部のモード文字列を自動的に受け入れていました (たとえば、r+b+)。 現在、無効なモード文字列は検出され、無効なパラメーターとして扱われます。

  • _O_U8TEXT モード

    現在、_setmode 関数は、_O_U8TEXT モードで開かれるストリームのモードを正しく報告します。 以前のバージョンのライブラリでは、そのようなストリームは _O_WTEXT で開かれるものとして報告されていました。

    エンコードが UTF-8 のストリームの _O_WTEXT モードをコードが解釈する場合、これは互換性に影響する変更です。 アプリケーションで UTF_8 がサポートされていない場合、増加するこの共通エンコードのサポートを追加することを検討してください。

  • snprintf および vsnprintf

    現在、snprintf 関数および vsnprintf 関数が実装されています。 古いコードは CRT ライブラリによって実装されていなかったため、これらの関数の定義マクロ バージョンを提供していました。しかし、新しいバージョンではこれらが不要になりました。 <stdio.h> を組み込む前に snprintf または vsnprintf がマクロとして定義されている場合、現在コンパイルは、マクロが定義された場所を示すエラーとともに失敗します。

    通常、この問題は、ユーザー コードの snprintf または vsnprintf の宣言を削除することによって修正されます。

  • tmpnam は使用可能なファイル名を生成する

    以前のバージョンでは、tmpnam 関数および tmpnam_s 関数は、ドライブのルートにファイル名を生成していました (\sd3c など)。 現在、これらの関数は、一時ディレクトリに使用可能なファイル名パスを生成します。

  • FILE カプセル化

    以前のバージョンでは、FILE 型が <stdio.h> で完全に定義されていたため、ユーザー コードが FILE に達して、その内部構造を変更することができました。 stdio ライブラリが変更され、実装に関する詳細が隠されるようになりました。 この一環として、現在、<stdio.h> で定義される FILE は不透明な型であり、そのメンバーは、CRT 自体の外部からアクセスできません。

  • _outp および _inp

    関数 _outp_outpw_outpd_inp_inpw、および _inpd が削除されました。

<stdlib.h>、<malloc.h>、および <sys/stat.h>

  • strtof および wcstof

    値を float として表せない場合に、strtof 関数と wcstof 関数は errno を ERANGE に設定できませんでした。 これは修正されました。 (このエラーはこれら 2 つの関数に固有のものでした。strtod 関数、wcstod 関数、strtold 関数、および wcstold 関数は影響を受けませんでした。) これはランタイムについて互換性に影響する変更点です。

  • 配置された割り当て関数

    以前のバージョンでは、配置された割り当て関数 (_aligned_malloc、_aligned_offset_malloc など) は、 配置が 0 のブロックに関する要求を自動的に受け入れていました。 要求された配置は 2 のべき乗でなければならず、ゼロは不可でした。 これは修正されており、配置 0 の要求は現在、無効なパラメーターとして扱われます。 これはランタイムについて互換性に影響する変更点です。

  • ヒープ関数

    _heapadd 関数、_heapset 関数、および _heapused 関数が削除されました。 Windows ヒープを使用するよう CRT が更新されたため、これらの関数は機能しなくなりました。

  • smallheap

    smalheap リンク オプションは削除されました。 「リンク オプション」を参照してください。

<string.h>

  • wcstok

    wcstok 関数のシグネチャが変更され、C 標準で必要なものと一致するようになりました。 以前のバージョンのライブラリでは、この関数のシグネチャは次のとおりでした。

    wchar_t* wcstok(wchar_t*, wchar_t const*)  
    
    

    strtok と同様、これはスレッドごとの内部コンテキストを使用して、呼び出しの状態を追跡していました。 現在、この関数は、シグネチャが wchar_t* wcstok(wchar_t*, wchar_t const*, wchar_t**) であり、呼び出し元がコンテキストを関数に対する 3 番目の引数として渡すことが必要とされます。

    古いシグネチャとともに新しい _wcstok 関数が追加され、移植が簡単になりました。 C++ コードをコンパイルする際にも、古いシグネチャを持つ wcstok のインライン オーバーロードが存在します。 このオーバーロードは、非推奨として宣言されます。 C コードでは、_CRT_NON_CONFORMING_WCSTOK を定義し、wcstok の代わりに _wcstok が使用されるようにすることもできます。

<time.h>

  • clock

    以前のバージョンでは、Windows API GetSystemTimeAsFileTime を使用して clock 関数が実装されていました。 この実装により、clock 関数はシステム時刻の影響を受け、単調になることがありませんでした。 現在は、QueryPerformanceCounter によって clock 関数が再実装されたため、単調になっています。

  • fstat および _utime

    以前のバージョンでは、_stat 関数、fstat 関数、および _utime 関数での夏時間の処理が正しくありませんでした。 Visual Studio 2013 より前では、これらの関数はすべて、標準時刻をあたかも夏時間にあるかのようにに調整していましたが、これは正しい処理ではありませんでした。

    Visual Studio 2013 では、_stat 関数ファミリでは問題が解決されましたが、fstat 関数ファミリと _utime 関数ファミリでは修正されていませんでした。 これは、関数間の不整合による問題につながっていました。 fstat および _utime の関数ファミリは現在修正され、これらすべての関数が、正確かつ一貫して夏時間を処理できるようになりました。

  • asctime

    以前のバージョンでは、asctime 関数は、1 桁の日の先頭をゼロで埋めていました (たとえば、Fri Jun 06 08:00:00 2014)。 この仕様では、そのような日の先頭を空白で埋める必要があります (たとえば、Fri Jun 6 08:00:00 2014)。 これは修正されました。

  • strftime および wcsftime

    現在、strftime 関数と wcsftime 関数は、書式指定子として %C、%D、%e、%F、%g、%G、%h、%n、%r、%R、%t、%T、%u、および %V をサポートしています。 さらに、E 修飾子と O 修飾子は、解析はされますが、無視されます。

    %c 書式指定子は、現行ロケールの "適切な日時の表記" を生成するものとして指定されます。 C ロケールでは、%a %b %e %T %Y と同じになるよう、この表記が必要です。 これは asctime によって生成される書式と同じです。 以前のバージョンでは、%c 書式指定子は MM/DD/YY HH:MM:SS 表記を使用して時刻を書式設定していましたが、これは正しくありませんでした。 これは修正されました。

  • timespec および TIME_UTC

    現在、<time.h> ヘッダーは、C11 標準から timespec 型と timespec_get 関数を定義します。 さらに、現在、timespec_get 関数で使用する TIME_UTC マクロが定義されています。 これは、そのいずれかの定義が競合しているコードに関して、互換性に影響する変更点です。

  • CLOCKS_PER_SEC

    現在、CLOCKS_PER_SEC マクロは type clock_t の型の整数に拡張されており、これは C 言語で必要です。

標準テンプレート ライブラリ

新しい最適化とデバッグのチェックを有効にするために、C++ 標準ライブラリの Visual Studio の実装では、バイナリの互換性がバージョンごとに意図的に保たれていません。 そのため、C++ 標準ライブラリを使用すると、異なるバージョンを使用してコンパイルされたオブジェクト ファイルとスタティック ライブラリは 1 つのバイナリ (EXE または DLL) に混在させることができず、C++ 標準ライブラリ オブジェクトは異なるバージョンを使用してコンパイルされたバイナリ間で渡すことができません。 混在があると、_MSC_VER の不一致に関するリンカー エラーが発生します (_MSC_VER はコンパイラのメジャー バージョンを含むマクロです。たとえば Visual Studio 2013 では 1800 です)。 このチェックでは、DLL の混在を検出できず、Visual C++ 2008 以前のバージョンが関係する混在も検出できません。

  • STL インクルード ファイル

    STL ヘッダーのインクルード構造に対していくつかの変更が加えられました。 STL ヘッダーは、指定されていない方法での相互インクルードを許可されています。 一般に、C++ 標準に応じて必要なすべてのヘッダーを注意深くインクルードし、どの STL ヘッダーにどの STL ヘッダーが含まれるかは関係ないようにするようコードを記述する必要があります。 これにより、バージョン間およびプラットフォーム間でのコードの移植が可能になります。 少なくとも Visual Studio 2015 でのヘッダーに関する 2 つの変更がユーザー コードに影響を与えます。 1 つ目として、<string> に <iterator> が含まれなくなりました。 2 つ目として、現在、<tuple> は、すべての <array> は含まない std::array を宣言します。これは、次のコード構成体の組み合わせによってコードに障害を起こす可能性があります。コードに "array" という名前の変数があり、using-directive "using namespace std;" があります。<tuple> を含む STL ヘッダー (<functional> など) を組み込みますが、これは現在、std::array を宣言します。

  • steady_clock

    steady_clock の <chrono> 実装が変更され、安定性と単調性のための C++ 標準の要件を満たすようになりました。 現在、steady_clock は QueryPerformanceCounter に基づき、high_resolution_clock は steady_clock の typedef です。 結果として、Visual C++ では現在、steady_clock::time_point は chrono::time_point<steady_clock> の typedef です。ただし、他の実装では異なる場合があります。

  • アロケーターおよび const

    現在、両サイドで const 引数を受け入れるには、アロケーターの等価/非等価の比較が必要です。 アロケーターがこれらの演算子を次のように定義するとします。

    bool operator==(const MyAlloc& other)  
    
    

    それを const メンバーとして宣言するために、これを更新する必要があります。

    bool operator==(const MyAlloc& other) const  
    
    
  • const 要素

    C++ 標準には常に、const 要素の禁止コンテナーがあります (vector<const T> や set<const T> など)。 Visual C++ 2013 以前では、そのようなコンテナーは受け入れられていました。 現在のバージョンでは、そのようなコンテナーをコンパイルすることはできません。

  • std::allocator::deallocate

    Visual C++ 2013 以前では、std::allocator::deallocate(p, n) は、n に対して渡されていた引数が無視されていました。 C++ 標準では常に、p を返した割り当ての呼び出しに最初の引数として渡される値と n が同等である必要がありました。 しかし、現在のバージョンでは、n の値が検査されます。 標準で必要なものとは異なる引数を n に渡すコードは、ランタイムにクラッシュする可能性があります。

  • hash_map および hash_set

    非標準ヘッダー ファイルの hash_map と hash_set は Visual Studio 2015 では推奨されておらず、将来のリリースでは削除されます。 代わりに unordered_map と unordered_set を使用してください。

  • 比較子および operator()

    現在、関連コンテナー (<map> ファミリー) では、比較子に const を呼び出せる関数呼び出し演算子がある必要があります。 比較子クラス宣言の次のコードは現在、コンパイルに失敗します。

    bool operator()(const X& a, const X& b)  
    
    

    このエラーを解決するには、関数の宣言を次のように変更します。

    bool operator()(const X& a, const X& b) const  
    
    
  • 型の特徴

    以前のバージョンの C++ ドラフト標準の型の特徴の古い名前が削除されました。 これらは C++11 で変更されており、Visual Studio 2015 では C++11 値に更新されました。 古い名前と新しい名前を次の表に示します。

    古い名前新しい名前
    add_referenceadd_lvalue_reference
    has_default_constructoris_default_constructible
    has_copy_constructoris_copy_constructible
    has_move_constructoris_move_constructible
    has_nothrow_constructoris_nothrow_default_constructible
    has_nothrow_default_constructoris_nothrow_default_constructible
    has_nothrow_copyis_nothrow_copy_constructible
    has_nothrow_copy_constructoris_nothrow_copy_constructible
    has_nothrow_move_constructoris_nothrow_move_constructible
    has_nothrow_assignis_nothrow_copy_assignable
    has_nothrow_copy_assignis_nothrow_copy_assignable
    has_nothrow_move_assignis_nothrow_move_assignable
    has_trivial_constructoris_trivially_default_constructible
    has_trivial_default_constructoris_trivially_default_constructible
    has_trivial_copyis_trivially_copy_constructible
    has_trivial_move_constructoris_trivially_move_constructible
    has_trivial_assignis_trivially_copy_assignable
    has_trivial_move_assignis_trivially_move_assignable
    has_trivial_destructoris_trivially_destructible
  • launch::any ポリシーと launch::sync ポリシー

    非標準の launch::any ポリシーと launch::sync ポリシーが削除されました。 代わりに、launch::any では、launch:async | launch:deferred を使用します。 launch::sync では、launch::deferred を使用します。 「launch 列挙型」を参照してください。

MFC と ATL

  • Microsoft Foundation Classes (MFC) はサイズが大きすぎるため、Visual Studio の "標準" インストールから除外されました。 MFC をインストールするには、Visual Studio 2015 セットアップでカスタム インストール オプションを選択します。 Visual Studio 2015 が既にインストールされている場合、MFC をインストールできます。そのためには、Visual Studio セットアップを再実行し、カスタム インストール オプションを選択し、Microsoft Foundation Classes を選択します。 Visual Studio セットアップの再実行は、コントロール パネル、プログラムと機能か、インストール メディアからすることができます。

    Visual C++ 再頒布可能パッケージにも、引き続きこのライブラリが含まれています。

同時実行ランタイム

  • concurrency::Context::Yield と競合する Windows.h の Yield マクロ

    以前、同時実行ランタイムは #undef を使用して Yield マクロの定義を解除し、Windows.h h で定義されている Yield マクロと concurrency::Context::Yield 関数の間の競合を回避していました。 この #undef は削除され、競合しない同等の新しい API 呼び出し concurrency::Context::YieldExecution が追加されました。 Yield との競合を回避するには、コードを更新して代わりに YieldExecution 関数を呼び出すか、次の例に示すように、呼び出しサイトで Yield 関数名を括弧で囲みます。

    (concurrency::Context::Yield)();  
    
    

作業の開始
Visual C++ 2013 での互換性に影響する変更点

表示: