新しい標準では、物事を行うための新しい方法があり、多くは古い方法よりも優れていますが、古い方法はまだ問題ありません。また、下位互換性の理由から、新しい標準が公式にあまり非推奨にならないことも明らかです。したがって、残っている問題は次のとおりです。
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ポインター定数を渡し始めるとすぐに、状況は急速に変化します。0
a 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つの利点は、またはができない ことです。つまり、体を見なくてもすぐにわかるので、そんなトリッキーはありません。break
return
for_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;
さらに悪いことに、これをデバッグしなければならなかった場合、これから出されるエラーメッセージがどれほど恐ろしいかを知っています。
ただし、これが「自明」かどうかはわかりません。
値による戻りは問題ではなくなりました。移動のセマンティクスや戻り値の最適化(コンパイラーに依存)を使用すると、オーバーヘッドやコスト(ほとんどの場合)がなく、コーディング機能がより自然になります。