2

あなたが持っているとしましょう

std::unordered_set<std::shared_ptr<A>> as;
// (there is an std::hash<std::shared_ptr<A>> specialisation)

そして、それを繰り返しながら、その要素のいくつかを置き換えたいと思います。

for (auto it = as.begin(); it != as.end(); ++it) {
  if ((*it)->condition()) {
    as.erase(it);
    as.insert(std::make_shared<A>(**it));
  }
}

これにより、および(再ハッシュが行われる場合)のイテレータが無効になる可能性があるため、このループは未定義の動作を示し、恐ろしくクラッシュする可能性があります。eraseinsert

私が考えることができる1つの解決策は、2つの別々のを使用してand操作vectorをバッファリングし、後でイテレータペアを使用して消去と挿入を行うオーバーロードを使用することです(これはおそらく再ハッシュに適しています)。inserterase

バッファアプローチを使用したとしても、これはまだ肥大化したコードのようであり、2回の再ハッシュが発生する可能性があり、両方とも不要になる可能性があります。

それで、それをするより良い方法はありますか?

4

4 に答える 4

1

私は(尋ねた直後に)可能なアプローチを考えましたが、もっと良いアプローチがあるかもしれません。

すべてをベクターにコピーしてから、ベクターからセットを再構築する方が高速です。

std::vector<std::shared_ptr> buffer;
buffer.reserve(as.size());
for (auto it = as.begin(); it != as.end(); ++it) {
  if ((*it)->condition()) {
    buffer.push_back(std::make_shared<A>(**it));
  } else {
    buffer.push_back(*it);
  }
}
as = std::unordered_set<std::shared_ptr<A>>(buffer.begin(),buffer.end());
于 2012-09-30T11:54:36.463 に答える
1

as.erase(it)イテレータを呼び出すitと無効になります。順序付けされていない連想コンテナに挿入すると、すべてのイテレータが無効になります。したがって、挿入はイテレータから分離する必要があります。新しく挿入されたオブジェクトの処理を回避するには、挿入を回避することも必要です。

std::vector<std::shared_ptr<A>> replaced;
for (auto it = as.begin(); it != as.end(); ) {
    if ((*it)->condition()) {
        replaced.push_back(std::make_shared<A>(**it));
        as.erase(it++);
    }
    else {
        ++it;
    }
}
std::copy(replaced.begin(), replaced.end(), std::inserter(as, as.begin());
于 2012-09-30T11:55:35.947 に答える
0

これを@bitmaskの答えへのコメントとして載せておきます。置き換えられた要素にベクトルを使用しないのはなぜですか?

std::vector<decltype(as)::value_type> buffer;
buffer.reserve(as.size());
for (auto it = as.begin(); it != as.end(); )
{
  if ((*it)->condition())
  {
    buffer.push_back(*it);
    it = as.erase(it);
  }
  else
  {
    ++it;
  }
}
as.insert(buffer.begin(),buffer.end());

そして、*itがすでにである場合shared_ptr<A>、私は再び理由を見ることができませんmake_shared()。代入して、コピーコンストラクタ/代入演算子に魔法を働かせてください。

于 2017-03-22T16:51:38.290 に答える
-1

あなたの場合、あなたは私の意見を交換することができます:

for(auto iter = as.begin(); iter != as.end(); ++iter)
{
    if(/*Check deletion condition here*/)
    {
        auto newItem = std::make_shared<A>(/*...*/);
        swap(*iter, newItem);
    }
}
于 2012-12-15T22:38:36.400 に答える