移動したコンテナを再利用しますか?


84

移動したコンテナを再利用する正しい方法は何ですか?

std::vector<int> container;
container.push_back(1);
auto container2 = std::move(container);

// ver1: Do nothing
//container2.clear(); // ver2: "Reset"
container = std::vector<int>() // ver3: Reinitialize

container.push_back(2);
assert(container.size() == 1 && container.front() == 2);

私がC ++ 0x標準ドラフトで読んだものから。ver3は正しい方法のようです。移動後のオブジェクトは、

「特に明記されていない限り、そのような移動元のオブジェクトは、有効であるが指定されていない状態に置かれるものとします。」

「他の方法で指定された」インスタンスは見つかりませんでした。

ver3は少し回り道で、ver1の方がはるかに好ましいと思いますが、vec3は追加の最適化を可能にしますが、一方で、簡単に間違いを引き起こす可能性があります。

私の仮定は正しいですか?


4
clear前提条件がないため(したがって、オブジェクトの状態に依存しないため)、を呼び出すことができます。
ニコルボーラス2012

@Nicol:std::vectorそのサイズへのポインタを格納する実装があったとしましょう(ばかげているようですが、合法です)。そのベクトルから移動すると、ポインタがNULLのままになる可能性があり、その後clearは失敗します。 operator=失敗する可能性もあります。
Ben Voigt

9
@Ben:「有効だが指定されていない」の「有効」部分に違反すると思います。
ildjarn 2012

1
@ildjarn:デストラクタを実行しても安全だと思っただけです。
Ben Voigt 2012

問題は「有効」とは何かということだと思います。
ronag 2012

回答:


97

仕様「有効だが指定されていない状態」のセクション17.3.26から:

オブジェクトの不変条件が満たされ、オブジェクトに対する操作がその型に対して指定されたとおりに動作することを除いて指定されていないオブジェクトの状態[例:x型のオブジェクトがstd::vector<int>有効であるが指定されていない状態にある場合、x.empty()無条件にx.front()呼び出すことができ、呼び出すことができますx.empty()falseを返す場合のみ。—例を終了]

したがって、オブジェクトはライブです。前提条件を必要としない任意の操作を実行できます(最初に前提条件を確認しない限り)。

clearたとえば、前提条件はありません。そして、オブジェクトを既知の状態に戻します。したがって、それをクリアして、通常どおりに使用します。


std :: vectorメソッドなどの「前提条件」については、標準のどこで読むことができますか?
ronag 2012

1
@ronag:§23.2には、それらがリストされているテーブルが含まれています。
グリズリー

2
私は興味深い次のことを見つけました、open-std.org / jtc1 / sc22 / wg21 / docs / papers / 2011 / n3241.html、彼らは「コンテナは「空よりも空になることができる」」と書いています。
ronag 2012

4
@ronag:1)コンテナが有効な状態にある場合、呼び出しclearは有効です。2)コンテナ不特定の状態clearにある間、標準で事後条件が義務付けられているため、呼び出すとコンテナは指定された状態になります(§23.2.3表100)。std::vector<T>クラス不変条件があるpush_back()(限り常に有効でTあるがCopyInsertable)。
ildjarn 2012

3
@ronag:open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3241.htmlは、「空よりも空」の引用に関する全国的なコメントの1つを引用していました。国のコメントは間違っていた。N3241はそのような状態を提案しませんでした。std :: containerの実装に、move-fromの結果として「空よりも空」の状態がある場合、その状態は有効な状態である必要があります(つまり、前提条件を必要としないオブジェクトで何でも実行できます)。
ハワードヒナント2012

11

オブジェクトが有効であるが未定義の状態にあるということは、基本的に、オブジェクトの正確な状態は保証されませんが、それは有効であり、そのようなメンバー関数(または非メンバー関数)は、依存しない限り機能することが保証されることを意味します特定の状態を持つオブジェクトに。

clear()メンバ関数は、したがって、オブジェクトから移動オンと呼ばれることができる(それはもちろん、有効であることを以外)オブジェクトの状態には前提条件を有していません。一方、たとえばfront()、コンテナが空でないことに依存しているため、空でないことが保証されていないため、呼び出すことはできません。

したがって、ver2とver3の両方で問題ないはずです。


ベクトルは常に空になりますが、一般的なケースには当てはまりません(IE配列)
Mooing Duck 2012

「ベクトルは常に空になります」、あなたはそれを何に基づいていますか?
ronag 2012

1
@ronag:もちろんver2とver3を意味しました(テキストから明らかなように、そのタイプミスを修正しました
Grizzly

興味深いことに、の前提条件は、に対してfront()のみ記載さstd::arrayれており、表には記載されていません。
Ben Voigt 2012

1
@Ben:§23.2.3表100は、の操作的意味論がでfront()ある*a.begin()と述べ、§23.2.1/ 6は「コンテナが空の場合、begin() == end()」と述べ、§24.2.1/ 5は「ライブラリは決して過去を想定しない-終了値は参照解除可能です。 "。したがってfront()、より明確にすることはできますが、の前提条件は推測できると思います。
ildjarn 2012

-8

移動元のオブジェクトでは何もできないと思います(破棄する場合を除く)。

swap代わりに、移動のすべての利点を取得しながら、コンテナを既知の状態のままにするために使用することはできませんか?


+1。スワップは良い考えですが、すべての場合に機能するとは限りません。たとえば、自動の使用は機能しません。たぶん、内部でスワップを使用するsafe_moveがアイデアかもしれませんか?
ronag 2012

5
これはライブオブジェクトであり、前提条件のない関数を使用できます(不変条件を
除く

のプライマリテンプレートにstd::swapは2つの移動割り当てがあり、それらの割り当てのターゲットは値から移動されます。それは私にとって「移動したオブジェクトに何かをする」と
見なさ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.