当我在迭代时,我可以从std :: list中删除元素吗?例如:
std::list<int> lst;
//....
for (std::list<int> itr = lst.begin(); itr != lst.end(); itr++)
{
if (*itr > 10)
lst.remove(*itr);
}
? 为什么?
答案 0 :(得分:33)
正确的代码如下:
for (std::list<int>::iterator itr = lst.begin(); itr != lst.end(); /*nothing*/)
{
if (*itr > 10)
itr = lst.erase(itr);
else
++itr;
}
当你从列表中删除一个项目时,你可能会使迭代器失效(如果它指向要删除的项目。)因此你需要使用erase
删除它(它返回一个指向下一个项目的有效迭代器) )。
更好的想法是使用std::remove_if
:
bool greater_than_10(int x)
{
return x > 10;
}
lst.remove_if(greater_than_10);
如果你的编译器支持lambdas,你可以把它缩短:
lst.remove_if([](int x){ return x > 10; });
(我没有测试这段代码,因为我的编译器不是那么新;感谢lambda函数从@John Dibling的答案中偷走了。)
实际上,从列表中删除会使only the iterators pointing to the item being deleted无效。但请注意,其他STL容器没有此属性。
因此,简而言之:一般来说,在迭代它时不应该从列表中删除项目,因为删除可能使迭代器无效(并且程序可能会崩溃)。但是,如果您完全确定删除的项目不是删除时使用的任何迭代器引用的值,则可以删除。
请注意,对于其他STL容器(例如向量),约束甚至更严格:从容器中删除不仅会使指向已删除项目的迭代器失效,还可能使其他迭代器失效!因此,在迭代它们时从这些容器中删除更有问题。
答案 1 :(得分:9)
没有。示例代码使itr
无效,从而导致未定义的行为。但这可行:
for (std::list<int>::iterator itr = lst.begin(); itr != lst.end(); )
{
if (*itr > 10)
itr = lst.erase(itr);
else
++itr;
}
答案 2 :(得分:3)
但你可以(而且应该)使用std::remove_if
以及一个写着“大于10”的仿函数,如下所示:
#include <list>
#include <algorithm>
int main()
{
std::list<int> lst;
lst.push_back(1);
lst.push_back(12);
lst.push_back(1);
//....
lst.erase(std::remove_if(lst.begin(), lst.end(), std::bind2nd(std::greater<int>(), 10)), lst.end());
}
另一种更通用的方法是编写自己的自定义函子。这是一个仿函数is_a_match
,如果要检查的值大于10,则返回true
。您可以重新定义operator()
以返回true
以对应于您的情况中的任何含义“匹配”:
#include <list>
#include <algorithm>
#include <functional>
struct is_a_match : public std::unary_function<int, bool>
{
is_a_match(int val) : val_(val) {};
bool operator()(int victim) const { return victim > val_; }
private:
int val_;
};
int main()
{
std::list<int> lst;
lst.push_back(1);
lst.push_back(12);
lst.push_back(1);
//....
lst.erase(std::remove_if(lst.begin(), lst.end(), is_a_match(10) ));
}
如果你有C ++ 0x符合编译器的好处,你也可以使用lambdas,它可以摆脱仿函数并在许多情况下编写更具表现力的代码
#include <list>
#include <algorithm>
int main()
{
std::list<int> lst;
lst.push_back(1);
lst.push_back(12);
lst.push_back(1);
//....
lst.erase(std::remove_if(lst.begin(), lst.end(), [](int v) {return v > 10;}));
}
答案 3 :(得分:0)
我认为你可以,但是你必须在删除元素后重新分配迭代器,这可以使用erase
方法而不是remove
来完成。
否则它将是不安全的,不应该这样做。
答案 4 :(得分:0)
有关迭代器的描述,请参阅http://www.cppreference.com/wiki/iterator/start。
几点说明:
++itr
)而不是增量后运算符(itr++
)