假设你有一个
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));
}
}
这可能使erase
和insert
上的迭代器无效(如果发生重新散列),因此此循环将显示未定义的行为,并且很可能会崩溃。
我能想到的一个解决方案是使用两个单独的vector
来缓冲insert
和erase
操作,然后使用带有迭代器对的重载进行擦除和插入(这个可能更有利于复兴。
即使我使用缓冲区方法,这仍然看起来很臃肿的代码,并且可能导致两次重访,这可能都是不必要的。
那么,有更好的方法吗?
答案 0 :(得分: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());
答案 1 :(得分: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());
答案 2 :(得分: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()
的理由。只需分配并让复制构造函数/赋值运算符发挥其魔力。
答案 3 :(得分:-1)
在你的情况下你可以交换我的观点:
for(auto iter = as.begin(); iter != as.end(); ++iter)
{
if(/*Check deletion condition here*/)
{
auto newItem = std::make_shared<A>(/*...*/);
swap(*iter, newItem);
}
}