2016-03-05 11 views
7

this talkによると、QtコンテナでC++ 11の範囲ベースforを使用すると、一定の落とし穴があります。考えてみましょう:QtでC++ 11レンジベースのforループを正しく使用する

QList<MyStruct> list; 

for(const MyStruct &item : list) 
{ 
    //... 
} 

落ち込みは、暗黙の共有に由来します。フードの下では、レンジベースのforはコンテナからイテレータを取得します。しかし、コンテナはconstではないので、インターレーターは非constであり、それは明らかにコンテナが分離するのに十分である。

これは簡単に修正できますが、const参照をコンテナに渡して強制的にconst_iteratorを使用し、デタッチしないようにします。

QList<MyStruct> list; 
const Qlist<MyStruct> &constList = list; 

for(const MyStruct &item : constList) 
{ 
    //... 
} 

ただし、たとえばコンテナは戻り値としてどうなりますか。

QList<MyStruct> foo() { //... } 

void main() 
{ 
    for(const MyStruct &item : foo()) 
    { 
    } 
} 

ここではどうなりますか?コンテナはまだコピーされていますか?直感的に言えば、これを行う必要があるかもしれないことを避けることだと思いますか?

QList<MyStruct> foo() { //... } 

main() 
{ 
    for(const MyStruct &item : const_cast<const QList<MyStruct>>(foo())) 
    { 
    } 
} 

わかりません。私はそれがもう少し冗長であることを知っていますが、私はこれを必要とします。

これまでコンテナをconst参照に変換するためにヘルパー関数を使用していましたが、同じ目的を達成するためのより簡単な方法があれば、聞いてみたいと思います。

+0

それを心配するのをやめてください。すべてのQtコンテナはCOWパターンを実装します。最新のバージョンでは、QtチームはC++ 11のサポートを実装しています。 –

+0

Btw、 'const MyStruct&const item:foo()'を使ってconstスタイルで反復処理してみてください。 –

+1

@SaZ私はあなたの提案をお試しになります。しかし、COWに関して、リンクされた会話のQt開発者は、コンテナから非constイテレータを作成すると、それが分離することを明示的に述べました。そうでなければ、イテレータを実際に使用してそれを変更したかどうかを検出することができなかったので、理にかなっています。 – Resurrection

答えて

4
template<class T> 
std::remove_reference_t<T> const& as_const(T&&t){return t;} 

です。 rvalueを返す暗黙的に共有されたオブジェクトは、非const反復のために暗黙的に書き込みシャラー(およびデタッチ)を検出できます。

これはあなたを与える:あなたは(かなりはっきりと)constの方法で反復処理することができます

for(auto&&item : as_const(foo())) 
{ 
} 

を。

あなたが動作するように、参照寿命延長が必要な場合は、2つのオーバーロードがあります。

template<class T> 
T const as_const(T&&t){return std::forward<T>(t);} 
template<class T> 
T const& as_const(T&t){return t;} 

しかし、constの右辺値を反復処理し、それを気には多くの場合、設計上のエラーです:場合、彼らはコピーを捨てている、なぜそれが重要ではありませんあなたはそれらを編集する?そして、あなたがconst資格に基づいて非常に異なった振る舞いをすると、それはあなたを他の場所で噛んでしまいます。

+0

as_constの2つのオーバーロードが必要であることが判明しました.1つはl値(T&)参照を与えられ、もう1つはr値(T &&)参照です(実際にはこの例で必要です)。両方とも同じ戻り値と内容を持っています。 – Resurrection

+0

@Resurrection oops。しかし、上記のように1つのオーバーロードで行うことができます。 – Yakk

+0

それは賢いです、ありがとう! – Resurrection

関連する問題