11
std::vector<int> a;
a.push_back(1);
a.push_back(a[0]);

上記のコードが非常に危険な場合があることを知りました。

(理由が明らかでない場合、あなたは一人ではありません... 私にも明らかではありませんでした。)

私の質問:

  1. それに対処する「標準的な」方法は何ですか?新しい変数を作成し、その後すぐに何かに割り当てるのは、私には少し奇妙に思えます。それに対処するより良い方法はありますか?

  2. このようなエイリアシングの問題に注意するために、どのように自分自身を訓練しますか? どのパターンを探しますか? この状況を認識できません。Cのキーワードについて学んだときにエイリアシングについて学んだrestrictだけで、問題が実際に何であるかを理解できるようになったのは今だけです。


編集:

私は答えを受け入れたいと思っていますが、質問の(2)の部分が答えられていないようです. 自分が書いたコードのエイリアシングの間違いを見つけるために、人々がどのような戦略を使用しているのか疑問に思っています。

これまでに思いついた戦略の 1 つは、2 つのパラメーターで同じ値を渡さないようにすることです。(この場合、1 つのパラメーターが暗黙的で、1 つが明示的です。)

他に簡単に気を付けたり注意したりすることはありますか?

4

5 に答える 5

5

編集: 技術的には、含まれている型に非スロー コピー コンストラクターがある場合、標準はこれが正しいことを義務付けていません。とにかくこれが成り立たない実装は知りません。push_back一般的な実装がすべての場合に同じように効率的である場合、2 つの実装を作成する必要があるからです。

エイリアシングは一般的に問題ですが、この特定のケースではそうではありません。コード:

assert( v.size() > 0 );
v.push_back( v[0] );

例外保証を通じて標準 (C++03) によって正確であることが保証されています (これは、独自のコンテナーを実装しない正当な理由であり、おそらくそれらを正しく取得できないでしょう)。特に §23.1 [lib.container.requirements] / 10 口述:

別段の指定がない限り (23.2.1.3 および 23.2.4.3 を参照) [注: これらの参照はどちらもinsertondequeおよびvectorそれぞれを参照する] この節で定義されているすべてのコンテナー タイプは、次の追加要件を満たしています。

— push_back() または push_front() 関数によって例外がスローされた場合、その関数は効果がありません

重要な点は、操作で例外がスローされた場合コンテナーは変更されずに残されるということです。これは、イテレーターが無効化されないことを意味します。つまり、例外が発生しないことが保証されるまで、メモリの元の領域が変更されないことを意味します。スローされます(デストラクタのしゃれを除いて)。一般に、コピー コンストラクターはスローできるため、実装では、オブジェクトを破棄する前にすべてのコピーが実行されるようにする必要があります。

これは、オブジェクトがある場所から別の場所にコピーされるのではなく、移動される C++0x でより顕著になります。新しい要素のコピーがスローされる可能性があるため、移動が実行される前に実行する必要があります。そうしないと、元のコンテナー内のオブジェクトの一部が無効化された状態になります。

于 2011-06-02T08:29:48.773 に答える
4

これは安全だと思います:

std::vector<int> a(1);
a.push_back(1);
a.push_back(int(a[0]));
于 2011-06-02T05:18:28.747 に答える
0

これはおそらくあなたにとって有用な答えではありませんが、「正しい」方法は、コンテナクラスがエイリアスを正しく処理する必要があるため、呼び出し元がそれについて心配する必要はありません。特に、push_back() (または同等のもの) は次のことを行う必要があります。

// C++-ish pseudo-code, exception-safety left as an exercise for the reader
void push_back(const T & t)
{
   if (current_size == alloced_size)
   {
      // Oops, our data array is full.  Time to trade it in for a bigger one
      T * newArray = new T[alloced_size*2];
      copy_items(newArray, current_array, current_size);
      newArray[current_size++] = t;
      delete [] current_array;    // delete old array only AFTER all references to t
      current_array = new_array;
      alloced_size *= 2;
   }
   else current_array[current_size++] = t;
}
于 2011-06-03T01:45:14.117 に答える
0

push_back(const T& el);実装では、配列または他の内部ストレージ内にあるかどうかを確認しますel。それが、そのような問題に対処する唯一の政治的に正しい方法です。

コンテナーは、これを別のコンテナー (別の安全規則) として処理する必要があります。

于 2011-06-02T05:20:56.210 に答える
-2

私はただこれを飛ばしているだけなので、福音とは考えないでください。しかし、これは機能しますか?

a.push_back(1);
a.push_back(&(new int(a[0])));
于 2011-06-02T05:18:38.073 に答える