C ++ 11にはどのような重大な変更が導入されていますか?


227

古いコードのコンパイルを停止させるC ++ 11の変更の少なくとも1つはexplicit operator bool()、標準ライブラリに導入され、operator void*()。確かに、これが機能しなくなるコードはおそらく最初から有効ではなかったはずのコードですが、それでもなお重大な変更です。以前は有効であったプログラムはもはや機能しなくなりました。

他に重大な変更はありますか?


1
exportキーワードの意味を削除しますか?コートをもらおう。
スティーブジェソップ2011年

7
私はそれをブールへの変換の変更を「破壊的な変更」とは呼びません...もっと「罰の変更」のように。
Xeo

4
そのような労働組合を作るために必要なすべての書類がただゴム印が付けられるのを待っているとき、確かに、なぜでしょうか?
Dennis Zickefoose

3
@Xeo: mystream.good()と同じではありませんbool(mystream)か?good()フラグが設定されていない場合はtrueです。bool(mystream)のみeofbitが設定されている場合でもfalseです。!mystream.fail()正しい同等物になります。
R.マルティーニョフェルナンデス

2
モデレーターのメモ:「質問または回答を手元に置いて、トピックに関するコメントを付けてください。質問または回答について話し合う場合、議論はそれについての質問または回答についてのみ行う必要があります。通常、討論はスタックオーバーフローに対して建設的ではありません。確かに敵対することはそうではない。
Tim Post

回答:


178

FDISには、付録C.2「C ++およびISO C ++ 2003」に非互換性に関するセクションがあります。

まとめ、FDISをここで言い換えると、SOの回答として(より良い)FDISが適切になるようにします。違いを説明するために、自分の例をいくつか追加しました。

ライブラリーに関連した非互換性がいくつかあり、その意味が正確にわからないため、他の人に詳しく説明するために残しておきます。

コア言語


#define u8 "abc"
const char *s = u8"def"; // Previously "abcdef", now "def"

#define _x "there"
"hello"_x // now a user-defined-string-literal. Previously, expanded _x .

新しいキーワード:alignas、alignof、char16_t、char32_t、constexpr、decltype、noexcept、nullptr、static_assert、およびthread_local


longで表すことができるよりも大きい特定の整数リテラルは、符号なし整数型から符号付きlong longに変更される可能性があります。


整数除算を使用する有効なC ++ 2003コードは、結果を0または負の無限大に向かって丸めますが、C ++ 0xは常に結果を0に丸めます。

(確かに、ほとんどの人にとって互換性の問題は実際にはありません)。


キーワードautoをストレージクラス指定子として使用する有効なC ++ 2003コードは、C ++ 0xでは無効になる場合があります。


変換を狭めると、C ++ 03との非互換性が発生します。たとえば、次のコードはC ++ 2003では有効ですが、この国際標準では無効です。doubleからintへの変換は狭まるためです。

int x[] = { 2.0 };

暗黙的に宣言された特別なメンバー関数は、暗黙的な定義が不適切な形式である場合に削除されたと定義されます。

これらの特別なメンバー関数のいずれかを、定義が不要なコンテキスト(たとえば、潜在的に評価されない式)で使用する有効なC ++ 2003プログラムは、不正な形式になります。

私の例:

struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }

そのようなsizeofトリックは一部のSFINAEで使用されており、今すぐ変更する必要があります:)


ユーザー宣言のデストラクタには、暗黙の例外指定があります。

私の例:

struct A {
  ~A() { throw "foo"; }
};

int main() { try { A a; } catch(...) { } }

このコードはterminateC ++ 0xでは呼び出されますが、C ++ 03では呼び出されません。A::~AC ++ 0x の暗黙の例外指定はだからですnoexcept(true)


を含む有効なC ++ 2003宣言exportは、C ++ 0xでは形式が正しくありません。


>直後に別の>が続く有効なC ++ 2003式は、2つのテンプレートを閉じるものとして扱われる場合があります。

C ++ 03では、>>常にシフト演算子トークンになります。


内部リンケージのある関数の従属呼び出しを許可します。

私の例:

static void f(int) { }
void f(long) { }

template<typename T>
void g(T t) { f(t); }

int main() { g(0); }

C ++ 03ではこれを呼び出しますf(long)が、C ++ 0xではこれを呼び出しますf(int)。C ++ 03とC ++ 0xの両方で、次の呼び出しが行われることに注意してくださいf(B)(インスタンス化のコンテキストでは、externリンケージ宣言のみが考慮されます)。

struct B { };
struct A : B { };

template<typename T>
void g(T t) { f(t); }

static void f(A) { }
void f(B) { }

int main() { A a; g(a); }

f(A)外部リンクがないため、より適切なマッチングは行われません。


ライブラリの変更

C ++ 0xのC ++標準ライブラリに追加された識別子を使用する有効なC ++ 2003コードは、コンパイルに失敗したり、この国際標準で異なる結果を生成したりする場合があります。


#includes新しいC ++ 0x標準ライブラリヘッダーの名前のヘッダーが有効なC ++ 2003コードは、この国際標準では無効である可能性があります。


スワップが存在することを期待してコンパイルされた有効なC ++ 2003コードには<algorithm>、代わりに<utility>


グローバル名前空間posixは標準化のために予約されています。


有効なC ++定義があること2003コードoverridefinalcarries_dependency、またはnoreturnマクロなどのC ++ 0xのでは無効です。


「内部リンケージを持つ関数の依存呼び出しを許可します。」2つの例の違いについて詳しく教えてください。明らかに何かが欠けています。
Dennis Zickefoose 2011年

@Dennis変更はopen-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561によって導入されました。彼らは事実についてコメントしていませんが、「インスタンス化コンテキスト」は、「同じ翻訳単位でのテンプレート特殊化のインスタンス化のポイントの前に宣言された外部リンケージを伴う宣言のセット」のみで構成されています。したがって、彼らが行った変更は、定義コンテキストでの検索にのみ影響します。
ヨハネスシャウブ-litb '19年

最初に挙げた例では、内部リンケージ関数が表示され、テンプレートの定義コンテキストで見つかりました。2番目の例では、内部リンケージ関数は、インスタンス化コンテキストの一部である必要があります。しかし、そうではないので、見つけることができません。
Johannes Schaub-litb

ちなみに、テンプレート定義コンテキストが内部リンケージのある関数を検出しても安全な唯一のケースは、関数テンプレートの特殊化が1つのTU(テンプレートが定義されている場所)で明示的にインスタンス化され、他のすべてのTUが依存している場合のみだと思いますその明示的なインスタンス化。他のすべての場合(他のTUが自分たちで特殊化をインスタンス化する場合)は、テンプレート定義に毎回異なる(内部リンケージ)関数を使用させることにより、ODRに違反します。
ヨハネスシャウブ-litb '19年

したがって、なぜインスタンス化コンテキストに制限があったのかはわかりません。インスタンス化は(明示的な)1つだけであり、そのインスタンス化はインスタンス化するTUのインスタンス化コンテキストにある内部リンケージ関数を使用します。定義コンテキストの場合と同じように。ちなみに、我々はまだ持っているならば、私が思うにexport、その後、私が思うに、他の時限は、明示的なインスタンスに依存する必要はありませんが、テンプレートthemselfsをインスタンス化できます。次に、インスタンス化のコンテキストで内部リンケージ関数が表示されるかどうかに影響します。
Johannes Schaub-litb '19年

28

autoキーワードの意味が変更されました。


9
autoキーワードを使用している場合、コードに非常に問題があります。なぜあなたはそれを使うのですか?
Elazar Leibovich '19年

これは重大な変更ではありません。のすべての有効なC ++ 03の使用はauto、C ++ 11でも有効です。
ドリュードーマン2014

11
@DrewDormann int main() { auto int i = 0; return i; }は完全に有効なC ++ 03ですが、C ++ 11の構文エラーです。C ++ 03モードでコンパイラーに与えることができる唯一の警告は、互換性に関する警告です。

24

重大な変化?

まあ、一つのことについて、あなたが使用している場合decltypeconstexprnullptr、などの識別子は、その後、あなたはトラブルになり得るような...


21

非互換性セクションでカバーされていないいくつかのコア非互換性:


C ++ 0xは、注入されたクラス名をテンプレートテンプレートパラメータへの引数として渡された場合はテンプレートとして、テンプレートタイプパラメータに渡された場合はタイプとして扱います。

有効なC ++ 03コードは、注入されたクラス名がこれらのシナリオで常に型になることに依存している場合、異なる動作をする可能性があります。私のclang PRから取得したサンプルコード

template<template<typename> class X>
struct M { };

template<template<typename> class X>
void g(int = 0); // #1

template<typename T>
void g(long = 0); // #2

template<typename T>
struct A {
  void f() {
    g<A>(); /* is ambiguous in C++0x */
    g<A>(1); /* should choose #1 in C++0x */
  }
};

void h() {
  A<int> a;
  a.f();
}

C ++ 03では、コードは2番目をg両方とも呼び出します。


C ++ 0xは、C ++ 03で依存していた一部の名前を現在は非依存にします。また、インスタンス化時に繰り返される現在のクラステンプレートのメンバーを参照する非依存修飾名の名前ルックアップが必要であり、これらの名前がテンプレート定義コンテキストで行われるのと同じ方法でルックアップすることの確認が必要です。

ドミナンスルールに依存する有効なC ++ 03コードは、この変更によりコンパイルできなくなる可能性があります。

例:

struct B { void f(); };

template<typename T>
struct A : virtual B { void f(); };

template<typename T>
struct C : virtual B, A<T> {
  void g() { this->f(); }
};

int main() { C<int> c; c.g(); }

呼び出しを行うこの有効なC ++ 03コードA<int>::fはC ++ 0xでは無効です。これは、インスタンス化時の名前のルックアップがとはA<int>::f対照的に見つかりB::f、at-definitionのルックアップと競合するためです。

現時点では、それがFDISの欠陥であるかどうかは不明です。委員会はこれを認識しており、状況を評価します。


最後の部分が基本クラスを示す修飾名の修飾子の最後の部分の識別子と同じであるusing宣言は、その名前のメンバーではなく、コンストラクターに名前を付けるようになりました。

例:

struct A { protected: int B; };
typedef A B;

struct C : B {
  // inheriting constructor, instead of bringing A::B into scope
  using B::B;
};

int main() { C c; c.B = 0; }

上記のコード例は、C ++ 03では整形式ですが、C ++ 0xでは整形式でA::Bはありませんmain


14

ストリーム抽出の失敗は別の方法で処理されます。

#include <sstream>
#include <cassert>

int main()
{
   std::stringstream ss;
   ss << '!';
   
   int x = -1;
   
   assert(!(ss >> x)); // C++03 and C++11
   assert(x == -1);    // C++03
   assert(x == 0);     // C++11
}

提案を変更

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23

標準参照

[C++03: 22.2.2.1.2/11]: ステージ2処理の結果は、次のいずれかになります。

  • charのシーケンスがステージ2で蓄積され、(の規則に従ってscanf)のタイプの値に変換されvalます。この値はに格納されvalios_base::goodbitに格納されerrます。
  • ステージ2で蓄積された文字のシーケンスによりscanf、入力エラーが報告された可能性があります。ios_base::failbitに割り当てられていerrます。[ed:には何も保存されていませんval。]

[C++11: 22.4.2.1.2/3]: [..]格納される数値は次のいずれかです。

  • ゼロ、変換関数がフィールド全体の変換に失敗した場合ios_base::failbitに割り当てられていerrます。
  • フィールドがで表現するには大きすぎる正の値を表す場合、最も正の表現可能な値valios_base::failbitに割り当てられていerrます。
  • 表現可能な最も負の値、または符号なし整数型の場合はゼロ(フィールドがで表現するには大きすぎる負の値を表す場合)valios_base::failbitに割り当てられていerrます。
  • それ以外の場合は、変換された値。

結果の数値はに格納されvalます。

実装

  • GCC 4.8 はC ++ 11に対して正しく出力します

    アサーション `x == -1 'が失敗しました

  • GCC 4.5-4.8 C ++ 03のすべての出力は次のとおりです。これはバグのようです。

    アサーション `x == -1 'が失敗しました

  • Visual C ++ 2008 ExpressはC ++ 03に対して正しく出力します。

    アサーションに失敗しました:x == 0

  • Visual C ++ 2012 ExpressはC ++ 11に対して誤って出力しますが、これは実装状況の問題のようです。

    アサーションに失敗しました:x == 0


13

明示的な変換演算子の導入はどのように重大な変化ですか?古いバージョンは、以前と同じように「有効」のままです。

はい、からoperator void*() constへの変更explicit operator bool() constは重大な変更になりますが、それ自体が間違っている方法で使用された場合のみです。適合コードは壊れません。

ここで、もう1つの重大な変更点は、集計の初期化中に変換を狭めることを禁止することです。

int a[] = { 1.0 }; // error

編集:覚えているだけstd::identity<T>で、C ++ 0xで削除されます(注を参照)。これは、型を依存型にする便利な構造体です。構造体は実際にはあまり機能しないので、これで修正されるはずです。

template<class T>
struct identity{
  typedef T type;
};

標準ライブラリオブジェクトに明示的な変換が追加されている場合、既存の暗黙的な変換が機能しなくなる可能性があります。しかし、変換が有効ではなく、何か有用なことをするシナリオは想像できません。
Dennis Zickefoose

導入は 、既存のを置き換える予定であるため、重大な変更operator void*です。
R.マルティーニョフェルナンデス2011

@Dennis:ああ、@ Martinhoの意味がわかります。しかし、人々が意図した以外にそれを使用した場合にのみ、それは重大な変更になります。
Xeo

「しかし、それ自体が内外で間違った方法で使用された場合のみ」bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }-C ++ 03の場合は、実際には何も問題はありませんが、C ++ 11ではエラーになっています。(注:GCC 4.9はまだoperator void*() constここにあるため、C ++ 11モードでコードを受け入れます。)

std::identity<T>C ++ 03の一部ではなかったため、C ++ 11では削除されませんでした。これはC ++ 11のドラフトに一時的に存在し、標準化の前にドラフトから削除されました。
ハワードヒナン


7

後方互換性を壊す暗黙の動きについて多くの議論がありました

関連する議論のある古いページ

コメントを読むと、暗黙の移動復帰も重大な変更です。


これらの議論の結果、ほとんどすべてのケースで削除されました。残ったものに問題はありますか?
Dennis Zickefoose 2011年

@デニス:はい。あなたの質問は、このフォローアップページで
Ben Voigt '19年

ああ、モバイルページにはコメントが表示されませんでした。いずれにせよ、それははるかに便利なリンクです...標準化プロセスの歴史的な奇妙さはそれほど関係ありません(私がその最初のドラフトを使用していると私が信じているMSVCを使用している場合を除きます)。
Dennis Zickefoose 2011年

@デニス:私はあなたが正しいと思います。私の答えのいくつかの周りにリンクを移動しました。
Ben Voigt

悲しいことに、cpp-next.comはもう存在しません。将来の参考のためにこれらはweb.archive.orgによって保存されたページである:暗黙の動きは、後方互換性の破壊関連する議論と古いページを
Max Truxa

6
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03:有効。

C ++ 0x: error: parameter declared 'auto'


2
@Xeo:コードはC ++ 03で有効です。タイプstruct xと名前のないパラメータです。
Ben Voigt '19年

私は誰かを捕まえることを望んでいた。@Xeoがコメントを読むことができなかったので、彼のコメントをすぐに削除できなかったことを願っています!
オービットでの軽さのレース

@Xeo:文法を掘り下げることなく、autoは有効なキーワードではないと確信しています。もしそうなら、それはおそらく期待どおりに機能しますが、適切に定義することはおそらく難しいでしょう。
Dennis Zickefoose 2011年

あなたが私を捕まえたとしましょう。それは文字通り構造体を無視しました。:)
Xeo

@Tomalek:Xeoは、C ++ 03には暗黙のintがないことを正しく指摘していました。
Ben Voigt '19年

-4

言語機能

  1. {}を使用した均一で一般的な初期化
  2. オート
  3. ナローイングの防止
  4. constexpr
  5. ループに基づく範囲
  6. nullptr
  7. 列挙型クラス
  8. static_assert
  9. std :: initializer_list
  10. 右辺値参照(セマンティクスの移動)
  11. >>
  12. ラムダス
  13. 可変テンプレート
  14. タイプとテンプレートのエイリアス
  15. Unicode文字
  16. long long integer型
  17. alignasおよびalignof
  18. decltype
  19. 生の文字列リテラル
  20. 一般化されたPOD
  21. 一般化された労働組合
  22. テンプレート引数としてのローカルクラス
  23. サフィックスの戻り値の型の構文
  24. [[carries_dependency]]と[[noreturn]]
  25. noexcept指定子
  26. noexcept演算子。
  27. C99の機能:
    • 拡張整数型
    • ナロー/ワイド文字列の連結
    • _ _ STDC_HOSTED _ _
    • _プラグマ(X)
    • 可変引数マクロと空のマクロ引数
  28. _ _ func _ _
  29. インライン名前空間
  30. コンストラクターの委任
  31. クラス内メンバー初期化子
  32. デフォルトと削除
  33. 明示的な変換演算子
  34. ユーザー定義リテラル
  35. 外部テンプレート
  36. 関数テンプレートのデフォルトのテンプレート引数
  37. コンストラクターの継承
  38. オーバーライドと最終
  39. よりシンプルでより一般的なSFINAEルール
  40. メモリモデル
  41. thread_local

標準ライブラリコンポーネント

  1. コンテナーのinitializer_list
  2. コンテナーの移動セマンティクス
  3. forward_list
  4. ハッシュコンテナ
    • unordered_map
    • unordered_multimap
    • unordered_set
    • unordered_multiset
  5. リソース管理のポインタ
    • unique_ptr
    • shared_ptr
    • weak_ptr
  6. 同時実行サポート
    • ミューテックス
    • ロック
    • 条件変数
  7. より高いレベルの同時実行サポート
    • packaged_thread
    • 未来
    • 約束する
    • 非同期
  8. タプル
  9. 正規表現
  10. 乱数
    • uniform_int_distribution
    • normal_distribution
    • random_engine
  11. int16_t、uint32_t、int_fast64_tなどの整数型名
  12. アレイ
  13. 例外のコピーと再スロー
  14. システムエラー
  15. コンテナーのemplace()操作
  16. constexpr関数
  17. noexcept関数の体系的な使用
  18. 機能してバインド
  19. 文字列から数値への変換
  20. スコープ付きアロケーター
  21. タイプ特性
  22. 時間ユーティリティ:期間とtime_point
  23. 比率
  24. quick_exit
  25. move()、copy_if()、is_sorted()などのその他のアルゴリズム
  26. ガベージコレクションABI
  27. アトミック

非推奨の機能

  1. コピーコンストラクターの生成と、デストラクターを持つクラスのコピー割り当て。
  2. 文字列リテラルをchar *に割り当てます。
  3. C ++ 98例外仕様
    • unexcepted_handler
    • set_unexpected
    • get_unexpected
    • 意外
  4. 関数オブジェクトと関連する関数
  5. auto_ptr
  6. 登録
  7. ++ブール値
  8. 書き出す
  9. Cスタイルのキャスト

3
これは質問の答えにはなりません。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.