新しい標準では、物事を行うための新しい方法があり、多くは古い方法よりも優れていますが、古い方法はまだ問題ありません。また、下位互換性の理由から、新しい標準が公式にあまり非推奨にならないことも明らかです。したがって、残っている問題は次のとおりです。
C ++ 11スタイルよりも確実に劣るコーディングの古い方法と、代わりに今できることは何ですか?
これに答えるには、「自動変数を使用する」などの明らかなことをスキップできます。
auto_ptrに非推奨です。
新しい標準では、物事を行うための新しい方法があり、多くは古い方法よりも優れていますが、古い方法はまだ問題ありません。また、下位互換性の理由から、新しい標準が公式にあまり非推奨にならないことも明らかです。したがって、残っている問題は次のとおりです。
C ++ 11スタイルよりも確実に劣るコーディングの古い方法と、代わりに今できることは何ですか?
これに答えるには、「自動変数を使用する」などの明らかなことをスキップできます。
auto_ptrに非推奨です。
回答:
finalクラスの派生を防ぐための指定子を提供しますstd::auto_ptr右辺値参照のファーストクラスサポートにより、動作が不必要になる魔法の方法。shrink_to_fit()メンバー関数を提供します。これにより、一時関数と交換する必要がなくなります。= delete構文は、特定の機能が明示的に拒否されていることを示すより直接的な方法です。これは、ヒープ割り当ての防止(つまり、=deleteメンバーの場合operator new)、コピーの防止、割り当てなどに適用できます。result_of:クラステンプレートの使用はresult_ofに置き換える必要がありdecltypeます。入手可能な場合にresult_of使用decltypeすると思います。NULLをとして再定義する必要nullptrがありますが、STLの話を見て、なぜそれを反対したのかを学んでください。やめようと思います!
result_of、リストから削除します。そのtypename前に必要な面倒なことにもかかわらず、私typename result_of<F(Args...)::typeは時々読みやすくなると思いますdecltype(std::declval<F>()(std::declval<Args>()...)、そしてN3436がワーキングペーパーに受け入れられて、彼らは両方ともSFINAEのために働きました(それは以前は提供decltypeしresult_ofなかった利点でした)
ある時点で、const値だけではなく値で戻る必要があると主張されました。
const A foo();
^^^^^
これはC ++ 98/03ではほとんど無害であり、次のようないくつかのバグをキャッチしている可能性もあります。
foo() = a;
しかしconst、C ++ 11では、移動のセマンティクスが阻害されるため、by by は禁忌です。
A a = foo(); // foo will copy into a instead of move into it
だからリラックスしてコーディングしてください:
A foo(); // return by non-const value
A& operator=(A o)&代わりにA& operator=(A o)。これらは愚かな間違いを防ぎ、クラスを基本的な型のように振る舞わせ、移動のセマンティクスを妨げません。
を放棄0してNULLを支持するようになったらすぐにnullptr、そうしてください!
非一般的なコードでは、0またはの使用NULLはそれほど重要ではありません。しかし、汎用コードでnullポインター定数を渡し始めるとすぐに、状況は急速に変化します。0a template<class T> func(T) Tに渡すとint、nullポインタ定数ではなく、として推定されます。そして、それをその後NULLポインター定数に戻すことはできません。これは、宇宙が使用されているだけでは存在しない問題の泥沼にカスケードしnullptrます。
C ++ 11は非推奨0ではなくNULL、nullポインター定数として使用します。ただし、コーディングしたようにコーディングする必要があります。
std::nullptr_t。
0またはNULLヌルポインタのために」)。
安全なブールイディオム → explicit operator bool()。
プライベートコピーコンストラクター(boost :: noncopyable)→ X(const X&) = delete
プライベートデストラクタと仮想継承を使用した最終クラスのシミュレーション →class X final
C ++ 11で基本的なアルゴリズムを作成することを避ける理由の1つは、標準ライブラリによって提供されるアルゴリズムと組み合わせたラムダの可用性です。
私は今それらを使用していますが、いまいましいループを再度書く必要がなく、count_if()、for_each()、または他のアルゴリズムを使用して、やりたいことをどれだけ頻繁に伝えるかは驚くべきことです。
完全なC ++ 11標準ライブラリでC ++ 11コンパイラを使用すると、 使用すると、標準のアルゴリズムを使用してを構築しないという言い訳はもうありません。ラムダはただそれを殺します。
どうして?
実際には(このアルゴリズムの記述方法を自分で使用した後)、意味を知るために暗号化を解除する必要があるいくつかのループよりも、何が行われるかを意味する単純な単語で構築されたものを読む方がはるかに簡単に感じられます。とはいえ、ラムダ引数を自動的に推定することは、構文を生のループと比較しやすくするのに役立ちます。
基本的に、標準的なアルゴリズムで作成されたアルゴリズムの読み取りは、ループの実装の詳細を隠す単語としてはるかに簡単です。
構築する低レベルのアルゴリズムがあるので、今考えなければならないのはより高レベルのアルゴリズムだけだと思います。
for_eachラムダを使用することは、ループ内のラムダの内容を使用して、同等の範囲ベースのforループよりも優れていることはわかりません。コードは多かれ少なかれ同じに見えますが、ラムダはいくつかの余分な句読点を導入します。同等のものを使用しboost::irangeて、明らかに反復子を使用するループだけでなく、より多くのループに適用できます。さらに、範囲ベースのforループには柔軟性があり、必要に応じて(returnまたはによってbreak)早く終了できるのに対し、for_eachスローする必要があります。
forにより、通常のit = c.begin(), const end = c.end(); it != end; ++itイディオムは機能しなくなります。
for_each範囲ベースのforループに対するアルゴリズムの1つの利点は、またはができない ことです。つまり、体を見なくてもすぐにわかるので、そんなトリッキーはありません。breakreturnfor_each
std::for_each(v.begin(), v.end(), [](int &i) { ++i; });と比較していfor (auto &i : v) { ++i; }ます。私は、柔軟性が両刃であることを受け入れます(goto非常に柔軟性があり、それが問題です)。私は考えていないように使用することができないという制約breakでfor_each、それは需要の余分な冗長性のために、バージョンを補償-のユーザーfor_eachここでは、IMOという理論的概念の一種のため、実際の読みやすさと利便性を犠牲にしているfor_eachで、原則的に明確にし、概念的よりシンプル。実際には、それは明確でも単純でもありません。
swap頻度の低いカスタムバージョンを実装する必要があります。C ++ 03では、swapコストのかかるコピーのスローを回避するために、効率的な非スローがしばしば必要ですstd::swap。2つのコピーを使用するため、swap多くの場合、カスタマイズする必要があります。C ++では、std::swap使用moveしているため、効率的でスローされない移動コンストラクターと移動代入演算子の実装に焦点が移ります。これらの場合、デフォルトで十分な場合が多いため、これはC ++ 03の場合よりも作業がはるかに少なくなります。
一般的にどのイディオムを使用するかは、経験を通じて作成されているため、予測するのは困難です。「効果的なC ++ 11」はおそらく来年、「C ++ 11コーディング標準」は必要な経験がまだないため、3年でしか期待できません。
名前はわかりませんが、C ++ 03コードでは、欠落した移動割り当ての代わりに次の構文を使用することがよくあります。
std::map<Big, Bigger> createBigMap(); // returns by value
void example ()
{
std::map<Big, Bigger> map;
// ... some code using map
createBigMap().swap(map); // cheap swap
}
これにより、swap上記と組み合わせたコピー省略によるコピーが回避されました。
mapとにかく戻り値を構築します。表示する手法mapは、単に構築するだけでなく、すでに存在する場合に役立ちます。この例は、「安いデフォルトコンストラクター」コメントがなく、その構造とスワップの間に「// ...」を付けたほうがよいでしょう
C ++ 11標準を使用しているコンパイラーが次のコードでエラーにならないことに気付いたとき:
std::vector<std::vector<int>> a;
おそらくオペレーターが含まれているため>>、私は踊り始めました。以前のバージョンでは、実行する必要がありました
std::vector<std::vector<int> > a;
さらに悪いことに、これをデバッグしなければならなかった場合、これから出されるエラーメッセージがどれほど恐ろしいかを知っています。
ただし、これが「自明」かどうかはわかりません。
値による戻りは問題ではなくなりました。移動のセマンティクスや戻り値の最適化(コンパイラーに依存)を使用すると、オーバーヘッドやコスト(ほとんどの場合)がなく、コーディング機能がより自然になります。