11

struct MyObject {
  MyObject(int value):value(value) { }
  MyObject(MyObject const&o):value(o.value) { }

  int value;
};

コピー コンストラクターが役立つだけでなく、何かを行うとします。それで

std::function<void()> f() {
  MyObject o;
  std::vector<int> v;
  return [=]() { /* use v and o */ &o; &v; }
}

vo最初に最初のラムダオブジェクトにコピーされますが、これで問題ありません。ただし、ラムダオブジェクトを移動する必要があるたびに、それらは再びコピーされます。v 移動できたとしても、そうではありません。これは、ラムダに暗黙的な移動コンストラクターoがなく、移動コンストラクターまたは単純なコピー コンストラクターがないためです。

誰かがこの背後にある理論的根拠を説明できますか?

4

2 に答える 2

6

これは、移動コンストラクターの暗黙的な生成をまったく望まない人と、ほとんどの状況で移動コンストラクターを自動的に生成することを望んでいる人の2つの極端な状況の間の妥協点であることを思い出しているようです。

移動コンストラクターの暗黙的な生成を望まない人々の中で、DaveAbrahamsはImplicitMoveMustGoという記事を書きました。ある状況下では、メンバーが移動可能であっても、moveコンストラクターの暗黙的な生成によって不変条件が壊れる可能性があるという理論的根拠があります。

今年(2011年)の初めに、委員会は、安全性の問題よりも既存のコードのパフォーマンスの向上を強調しているように見える決定で、moveコンストラクターの暗黙的な生成を維持することを決定しました 1 。決定の詳細、賛否両論については話していませんが、結果にも満足していません。

編集(Jerry Coffinから):移動コンストラクターの暗黙的な宣言の条件のリストは次のとおりです。

If the definition of a class X does not explicitly declare a move constructor, 
one will be implicitly declared as defaulted if and only if
— X does not have a user-declared copy constructor,
— X does not have a user-declared copy assignment operator,
— X does not have a user-declared move assignment operator,
— X does not have a user-declared destructor, and
— the move constructor would not be implicitly defined as deleted.

基本的な考え方は、これらのいずれかをクラスに含めることは、暗黙的に生成されたmovectorが誤動作する可能性が高いことを示しているということです。それは事実ですが、リスト内の条件は決定に必要でも十分でもないため、有用であったはずの多くのムーバーが生成されず、問題を引き起こす多くのムーバーが生成される可能性があります。さらに悪いことに、ルールはすでに長く複雑であるため、すべてを覚えている人はほとんどいません。ルールを修正すると、おそらく少なくとも2倍になります。
[ジェリーの貢献/暴言の終わり]

(1)決定が下された理由についての洞察を与えてくれたGeneBushuyevに感謝します

于 2011-11-29T23:21:31.887 に答える
1

ちょっと推測ですが、例外と関係があるのではないかと思います。つまり、ムーブ コンストラクターは実際には noexcept である必要がありますが、ムーブ コンストラクターがコピー コンストラクターを呼び出すと、それがスローされる可能性があります。

(ここから私の記憶をリフレッシュしようとしています。これでこの問題がカバーされたと思います)

追加するために編集:

そして、私の推測は間違っていました。私の知る限り、正解はここからです。コピー コンストラクターの存在は、クラスに不変条件があることを示しており、デフォルトで生成された移動コンストラクターはそれらの不変条件を尊重しない可能性があるため、生成すべきではありません。

于 2011-11-29T22:59:36.657 に答える