2

配列std::vector<Foo>があり、すべてのfooを繰り返し処理して、次のように実行したいとします。

for (auto foo : vecFoo)
    foo.x = 10;

これは、vecFooのコンテンツへの参照ではなく、コンテンツのローカルコピーを作成するため、何もしません。正しいループは次のとおりです。

for (auto& foo : vecFoo)
    foo.x = 10;

これは私が今何度か犯した間違いなので、間違ったときに私を捕まえる解決策を見つけたいと思います。構造体に対してできること、またはオンにできる警告フラグのいずれかで満足しています。のコピーコンストラクターをプライベートにしようとしましFooたが、それができなくなってしまいますpush_backemplace_backこれは明らかに私が望んでいることではありません。

4

3 に答える 3

4

根本的な問題への答えは学習です。何度か間違えると、経験から学ぶことになります。

コンテナーに格納されている型を完全に制御できる特定の場合の言語トリックとして、nothrow移動コンストラクターを提供し、コピー構築を無効にすることができます。そのためには、を使用する必要がありますemplace_back(またはでセマンティクスを移動しpush_backます)。

それでも、これはこの特定の場合にエラーをトリガーする方法にすぎませんが、100%制御できないタイプを格納する場合(つまり、コピー構築を無効にしたり、移動構築を追加したり、nothrow移動コンストラクターを実装したりすることはできません-それがスローされないことを保証することはできません)それからあなたは運が悪いです、それは最初の文につながります:参照を使うことを学びます

于 2012-09-04T16:27:47.317 に答える
1

これは私が何度か犯した間違いなので、間違ったときに私を捕まえる解決策を見つけたいと思います.

私の経験では、最善の解決策は、オブジェクトを常にconstデフォルトで宣言するようにトレーニングすることです。これにより、それらを変更しようとすると、コンパイラによってチェックされるエラーになります。それを行うと、コンパイラは、オブジェクトを書き込み可能にするためにそれから逸脱するのを忘れたときに、そのような宣言をキャッチします。

// This is what my hands write by default:
int const x = 42;

私はいつもこのように書くようにしています。次に、コードで次のように表示されるたびに:

int y =  42;

私の心は、変数が実際に変更可能であるべきかどうかを理解しようとします。ありがたいことに、C++ 11 では range-for ループでもこれが許可されているため、この考え方をループの例に適応させることができます。

for (auto const i : vecFoo)
    i.foo = 10; // error

もちろん、これはconstすべてを自動的に訓練した後にのみ機能します。

これは完璧とはほど遠いものであり、かなりの運動が必要であることに同意します. 何人かの人々が繰り返し指摘しているように、最善の解決策は、C++ がデフォルトで宣言を考慮constすることです (実際、少なくともラムダでキャプチャされた値の場合はそうです) が、その船は出航しました。

于 2012-09-04T16:17:12.600 に答える
1

私が求めているのは、そのような間違いを犯す機会がないように、そのコピーを私のクラスでは無効にする方法です。

C++11 を使用すると、クラスをコピー不可にすることが簡単になります。コピー コンストラクター/代入演算子を削除するだけです (コンパイラーがその C++11 機能をサポートしていると仮定します)。

class SomeClass
{
public:
  SomeClass(const SomeClass &) = delete;
  SomeClass &operator=(const SomeClass &) = delete;

...
};

コピー コンストラクターを呼び出そうとすると、コンパイラ エラーが発生します。この構文をまだサポートしていない Visual Studio を使用している場合は、標準の C++03 イディオムを使用する必要があります。つまり、コピー コンストラクターをプライベートに宣言します。


ベクターにコピーできないため、ベクターで構造体を使用できなくなりました。

できますよ。コピーが必要な機能は使用できません。push_backand の使用をandinsertに置き換える必要がemplace_backありますemplace

注意: コピー コンストラクターと代入演算子を宣言する場合は、それらを削除するだけでも、移動コンストラクター/代入演算子を手動で宣言する必要があります。もちろん、構文を使用できます。= default

于 2012-09-04T16:59:08.327 に答える