これらの問題は、C ++標準に準拠するためのコンパイラへの多数の変更、関数シグネチャの変更、またはメモリ内のオブジェクトの場所の変更によって発生する可能性があります。
実行時エラー(最も見つけにくいことがわかっている)を回避するために、別のバージョンのコンパイラが受け取ったバイナリファイルと静的リンクを作成しないことをお勧めします。 また、プログラム(EXEまたはDLL)を更新するときは、使用するライブラリも新しいバージョンのコンパイラでコンパイルされていることを確認してください。
CRT(Cランタイム)またはSTL(標準テンプレートライブラリ)の型を使用する場合は、異なるバージョンのコンパイラでコンパイルされたバイナリ(DLLを含む)間で型を転送しないでください。 この問題については、 DLLの境界を越えてCRTオブジェクトを渡す潜在的なエラーで詳しく説明します 。
また、将来的には、メモリ内のオブジェクトの特定の場所に依存するコードを作成しないことをお勧めします(COMインターフェイスまたはPODオブジェクトでない限り)。 そのようなコードがある場合、コンパイラを更新した後、すべてが正常に機能することを確認する必要があります。 詳細については、 ABI境界での移植性(Modern C ++)を参照してください 。
次の記事では、Visual C ++コンパイラ(Visual Studio 2015 Previewに付属)の変更について説明します。 この記事では、「新しい動作」と「今」という言葉はこのバージョンを正確に指し、「古い動作」と「以前の」はVisual Studio 2013(および以前のバージョン)を指します。
要約:
-コンパイラの変更
-Cランタイムライブラリ(CRT)の変更
-STLの変更
-MFCおよびATLの変更
コンパイラの変更
- / Zc:forScope-コンパイラフラグ
/Zc:forScope-
非推奨であり、今後削除されます。 このフラグを使用すると、コンパイラは警告D9035をスローします。
このフラグは、非標準のC ++拡張機能(このループ外のfor
ループの説明で宣言された変数の使用)を使用するために使用されます。 このフラグは、別のフラグが設定されている場合にのみ必要です-/Za
( 標準に準拠 )/Za
がない場合、ループ記述からの変数の使用はデフォルトで有効になっています。 クロスプラットフォームを心配する必要がない場合(たとえば、他のコンパイラーによるコードの収集を目的としていない場合)、/Za
フラグをオフにすることができます(プロジェクトプロパティ「Disable Language Extensions」を「No」に設定します)。 クロスプラットフォームと標準への準拠を重視する場合は、変数宣言をループの上に移動して、このようなコードのセクションを書き換える必要があります。
// 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
/Zg
コンパイラフラグ( プロトタイピング関数 )は使用できなくなりました(以前は非推奨の属性でした)
- これで、mstest.exeを使用してコマンドラインからC ++ / CLIを使用して単体テストを実行できなくなり、代わりにvtest.console.exeを使用する必要があります。 詳細については、 VSTest.Console.exeコマンドラインオプションを参照してください 。
- 可変キーワード
現在、標準に従ってmutable
の使用はクラスメンバーの名前にのみ適用でき、リンク、またはconst
またはstatic
として宣言された名前には適用できません。 例:
struct S { mutable int &r; };
これはコンパイルに使用されていましたが、現在コンパイラはエラーC2071をスローします。 修正するには、mutable
を削除するだけです。
- char_16_tおよびchar_32_t
現在、char_16_tおよびchar_32_tはユーザータイプのエイリアスとして使用できません。これらのタイプは組み込みとして定義されているためです。 ライブラリ作成者がchar_16_tとchar_32_tをそれぞれuint_16_tとuint_32_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; }
修正するには、エイリアスの宣言を削除し、新しく入力したものと競合する他の識別子の名前を変更する必要があります。
- 非型テンプレートパラメータ
型の互換性について、非標準のテンプレートパラメータを含むコードが正しくチェックされるようになりました。 たとえば、次のコードはエラーなしでコンパイルするために使用されました。
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>(); }
テンプレートパラメータの型が渡された引数の型と一致しないため、コンパイラはエラーをスローします(パラメータの型は定数メソッドへのポインタですが、fは定数ではありません)。
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(位置合わせ)
コンパイラーは、関数の__declspec(align)
を受け入れなくなりました。 実際、彼は決して受け入れませんでしたが、今ではエラーC3323を出します。 それを取り除くには、関数宣言からこの式を削除するだけです。 これは以前は効果がなかったため、プログラムの内容は変更されません。
- 例外処理
例外処理にはいくつかの変更があります。 まず、例外オブジェクトはコピー可能で移動可能でなければなりません。 以前は、同様のコードがコンパイルされていましたが、現在はエラーが発生します。
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でコンパイルされますが、現在はエラーが発生します。
struct B { public: B(); private: B(const B &); }; struct D : public B { }; int main() { try { } catch (D d) // error { } }
このエラーは、リンクで例外を受け入れることで修正できます。
catch(D& d) { }
- 行とマクロ
コンパイラーは、ユーザー定義リテラル(UDL)をサポートするようになりました。 この結果、文字列(正確には文字列リテラル)の後にスペースのないマクロが続くと、UDLとして解釈され、エラーまたは予期しない結果が生じる可能性があります。 たとえば、以前は問題なくコンパイルされていました。
#define _x "there" char* func() { return "hello"_x; } int main() { char * p = func(); return 0; }
コンパイラは、func関数によって返された値を文字列「hello」と解釈し、「there」に展開されたマクロを2つのリテラルを1つに結合しました。 現在、コンパイラはこれをUDLとして解釈しますが、知っているUDLの中から_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?
この問題を解決するには、行とマクロの間にスペースを入れる必要があります。
- 近くの列
前のケースと同様に、文字列の解析の変更により、スペースを共有しない文字列リテラルの隣同士の構築は以前は単一行として解釈されていましたが、正しいコンパイルのためにスペースを追加する必要があります:
char * str = "abc""def";
行間にスペースを追加するだけです:
char * str = "abc" "def";
- 新規ホスティングと削除
C ++ 14標準に準拠するために、delete
演算子の動作が変更されました。 詳細は、 C ++ Sized Deallocationに記載されています。 オブジェクトのサイズを取るグローバルdelete
演算子の形式が追加されました。 この変更の重要性は、コードに(ホストのnew
演算子に対応する)同じ署名のdelete
演算子がある場合、コンパイラがこの場所で決定しようとしているため、コンパイルエラー(new
演算子を使用する行を指すC2956)が発生することです適切なdelete
演算子)。
関数void operator delete(void*, size_t)
は、C ++ 11の配置演算子new
-void* operator new(size_t, size_t)
の関数に対応する配置演算子delete
でした。 新しいC ++ 14標準では、このdelete
通常の割り当て解除関数(つまり、グローバルdelete
演算子)になりました。 標準では以下が必要です-ホストnew
が対応するdelete
を探し、標準機能を見つけた場合、プログラムはコンパイルされません。
たとえば、コードでホストnew
およびdelete
定義するとします。
void * operator new(std::size_t, std::size_t); void operator delete(void*, std::size_t) noexcept;
ここでの問題は次のとおりです。delete
行う演算子の説明は、新しいグローバル演算子の説明と一致します。 このような一致を避けるために、new
およびdelete
演算子でサイズを記述するときに、size_t以外のタイプを使用できます。 ここでは、size_tがコンパイラに依存することを考慮する必要があります。VisualC ++では、これはunsigned intのエイリアスです。 ここでの良い解決策は、列挙を使用することです。
enum class my_type : size_t {};
次に、new_の宣言を変更し、size_tの代わりにmy_typeを2番目のパラメーターとして受け入れるように配置演算子をdelete
必要があります。 また、new
呼び出しへの引数の転送を修正し(たとえば、static_cast<my_type>
を使用して整数値から列挙に変換する)、配置演算子の定義を変更して、列挙から整数型に変換する必要があります。 リストに加えて、たとえば、size_t型のフィールドを持つクラスを使用できます。
代替ソリューションとして、ホストnew
削除できます。 コードがnew
ホストを使用してプールを実装し、渡されるサイズがホストまたは削除するオブジェクトのサイズである場合、新しいdelete
演算子はこのプールの削除に適している可能性があります。
コード内でこれらの演算子の動作を今すぐ変更したくない場合は、今のところ/ Zc:sizedDealloc-フラグを使用して、古い動作を返します。 つまり、2引数の削除関数は作成されないため、定義した削除関数と競合することはありません。
- ユニオンデータメンバー
リンクをユニオンフィールドにすることはできなくなりました。 このコードはコンパイルに使用されていましたが、現在では実行されません
union U1 { const int i; }; union U2 { int &i; }; union U3 { struct {int &i;}; };
現在、次のエラーが発生します。
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
この問題を解決するには、ポインタまたは通常の値へのリンクを変更する必要があります。 型をポインターに変更するには、このフィールドにアクセスするコードを変更する必要があります。 タイプを値に変更すると、ユニオンの値を変更できるようになり、ユニオンの他のフィールドに影響します。 また、この場合、ユニオンのサイズが変更される場合があります。
- 名前のない組合(匿名組合)
名前のない協会は、標準に沿ったものになりました。 以前は、匿名の関連付けの場合、明示的なコンストラクターとデストラクターが生成されていました。 現在、それらは削除済みと宣言されています。
struct S { S(); }; union { struct { S s; }; } u; // C2280
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
この問題を解決するには、コンストラクターまたはデストラクタを定義する必要があります
struct S { // , S() {} }; union { struct { S s; }; } u;
- 匿名構造との関連付け
標準への準拠を保証するために、関連付け内の匿名構造のメンバーの実行時の動作が変更されました。 匿名構造のコンストラクター(関連付けのメンバー)は、関連付けが作成されるときに暗黙的に呼び出されることはなくなりました。 また、このようなフィールドのデストラクタは、ユニオンが可視性ブロックから出るときに暗黙的に呼び出されることはありません。 例:
#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; }
以前は、コンストラクタとデストラクタの両方が呼び出されていました。 今では呼び出されません。 コンパイラーは警告を生成します。
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 <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として知られる原則が使用されているため)。
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): 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
と [ T = D U = D ]
エラーの理由は、is_base_of
の最初の呼び出しの場所でis_base_of
クラスDがまだ定義されていないためです。
この場合、エラー修正は次のようになります。クラスを定義する前にそのような型チェックを使用する必要はないため、BとD dの定義をファイルの先頭に転送する必要があります。 これらの定義がヘッダーファイルにある場合、問題のあるテンプレートが使用される前に、クラス定義が含まれていることを確認するために、包含順序を確認する必要があります。
- コンストラクターをコピーする
Visual Studio 2013とVisual Studio 2015 RCの両方で、このクラスにユーザー定義の移動コンストラクターがあり、ユーザー定義のコピーコンストラクターがない場合、コンパイラーはクラスのコピーコンストラクターを作成します。 Dev14では、この暗黙的に生成されたコピーコンストラクターは「=削除」としてマークされます。
Cランタイムライブラリ(CRT)の変更
一般的な変更
- バイナリファイルのリファクタリング
CRTライブラリは、2つのバイナリファイルに分割されました。標準CRTライブラリ(Universal CRT-ucrtbase)は、ほとんどの標準機能を含み、VCランタイムライブラリ(vcruntime140)は、コンパイラ依存機能(例外処理や組み込み関数(組み込み関数))。 標準のプロジェクト設定を使用する場合、リンカーはこれらの新しいライブラリを自分で使用するため、この変更による影響はありません。 Ignore All Default LibrariesのプロジェクトリンカープロパティをYesに設定した場合、または/ NODEFAULTLIBリンカーフラグを使用した場合は、ライブラリのリスト(プロジェクトプロパティAdditional Dependencies )を更新する必要があります。つまり、自分で新しいライブラリを含めます。 むしろ、古いCRTライブラリ(libcmt.lib、libcmtd.lib、msvcrt.lib、msvcrtd.lib)を新しい同等のものに置き換えます。 2つの新しいライブラリにはそれぞれ、静的(.lib)バージョンと動的(.dll)バージョンのほか、リリースビルド(サフィックスなし)とデバッグビルド(サフィックス「d」付き)があります。 詳細はこちら: CRTライブラリの機能
<locale.h>
- localeconv
スレッドごとのロケールが有効になっている場合、locale.hで宣言されたlocaleconv関数が正しく機能するようになりました。 以前、この関数はIconvグローバルロケールを返しましたが、ストリーミングロケールは返しませんでした。
ストリーミングロケールを使用する場合は、新しいlocaleconvの動作がプログラムにどのように影響するかを確認する必要があります。
<math.h>
- C ++ライブラリ関数のオーバーロード
以前は、すべてではありませんが、いくつかの数学ライブラリ関数が<math.h>
オーバーロードされていました。. , <math.h> .
<math.h>
.
IEEE-754 F C11, (NaN ). , NaN , - . : IEEE 754 Standard , Annex F of the C11 Standard .
, - .
FLT_ROUNDS
, , (, fesetround). FLT_ROUNDS .
の. , <math.h> .
<math.h>
.
IEEE-754 F C11, (NaN ). , NaN , - . : IEEE 754 Standard , Annex F of the C11 Standard .
, - .
FLT_ROUNDS
, , (, fesetround). FLT_ROUNDS .
. , <math.h>
.<math.h>
.
IEEE-754 F C11, (NaN ). , NaN , - . : IEEE 754 Standard , Annex F of the C11 Standard .
, - .
FLT_ROUNDS
, , (, fesetround). FLT_ROUNDS .
<new>および<new.h>
- 新規および削除
ライブラリの以前のバージョンでは、実装依存の演算子newおよびdeleteが動的ライブラリ(たとえば、msvcr120.dll)からエクスポートされていました。 これらの演算子は、動的ライブラリが使用されている場合でも、常に静的にバイナリとリンクするようになりました。
これは、ネイティブコードまたは混合コード(/ clr)にとってそれほど重要な変更ではありませんが、 / clr:pureフラグを使用してコードをコンパイルすると、コードの更新後にコンパイルが停止する場合があります。 この場合、ヘッダーファイル<new.h> . : /clr:pure .
すべて適切な場所に接続されていることを確認する必要があります<new.h>
. : /clr:pure .
<new.h>
. : /clr:pure .
- 新規および削除