C++ 删除外部迭代器
我尝试了以下代码C++ 删除外部迭代器,c++,iterator,erase,C++,Iterator,Erase,我尝试了以下代码 list<int> a ={1,2}; list<int> b ={3,4}; a.erase(b.begin()); for (auto x:b) cout << x << endl; 奇怪的是,程序运行良好,没有任何错误。打印出来的是4。我想知道,当对象已经隐式地存在于迭代器中时,为什么擦除是一个成员函数。这只是未定义的行为,所以任何事情都可能发生,而您观察到的任何事情在某种程度上都是预期的行为 不要这样做 显然,std::
list<int> a ={1,2};
list<int> b ={3,4};
a.erase(b.begin());
for (auto x:b) cout << x << endl;
奇怪的是,程序运行良好,没有任何错误。打印出来的是4。我想知道,当对象已经隐式地存在于迭代器中时,为什么擦除是一个成员函数。这只是未定义的行为,所以任何事情都可能发生,而您观察到的任何事情在某种程度上都是预期的行为
不要这样做
显然,std::list::erase的前提条件是参数是容器元素的迭代器。这只是未定义的行为,因此任何事情都可能发生,而您观察到的任何事情在某种程度上都是预期的行为
不要这样做
显然,std::list::erase的前提条件是参数必须是容器元素的迭代器
这将调用未定义的行为,因为您正在将从一个容器获得的迭代器传递给另一个容器的函数。a和b是两个不同的容器,它们不一样
未定义的行为意味着任何事情都可能发生:它可能按预期运行,也可能不按预期运行。语言规范和编译器都不能保证它能正常工作。可以恰当地说是未定义的行为
你应该做的是:
auto value = *(b.begin()); //value is int
auto it = std::find(a.begin(), a.end(), value); //returns iterator
if ( it != a.end())
a.erase(it); //well-defined, as the iterator belongs to the same container!
或者,如果要删除所有等于value的元素,则可以简单地执行以下操作:
a.remove(value); //std::list has remove member function
但是,如果您使用std::vector,那么在大多数情况下都应该使用它。它是C++中的默认容器类型,只有在有充分理由这样做时,才应该使用STD::List:
std::vector<int> a ={1,2};
std::vector<int> b ={3,4};
//if you want to remove one element:
auto value = *(b.begin()); //value is int
auto it = std::find(a.begin(), a.end(), value); //returns iterator
if ( it != a.end())
a.erase(it); //well-defined, as the iterator belongs to the same container!
注意,std::vector没有remove member函数,这就是为什么要应用这个习惯用法。您可以阅读其中更详细的讨论
这将调用未定义的行为,因为您正在将从一个容器获得的迭代器传递给另一个容器的函数。a和b是两个不同的容器,它们不一样
未定义的行为意味着任何事情都可能发生:它可能按预期运行,也可能不按预期运行。语言规范和编译器都不能保证它能正常工作。可以恰当地说是未定义的行为
你应该做的是:
auto value = *(b.begin()); //value is int
auto it = std::find(a.begin(), a.end(), value); //returns iterator
if ( it != a.end())
a.erase(it); //well-defined, as the iterator belongs to the same container!
或者,如果要删除所有等于value的元素,则可以简单地执行以下操作:
a.remove(value); //std::list has remove member function
但是,如果您使用std::vector,那么在大多数情况下都应该使用它。它是C++中的默认容器类型,只有在有充分理由这样做时,才应该使用STD::List:
std::vector<int> a ={1,2};
std::vector<int> b ={3,4};
//if you want to remove one element:
auto value = *(b.begin()); //value is int
auto it = std::find(a.begin(), a.end(), value); //returns iterator
if ( it != a.end())
a.erase(it); //well-defined, as the iterator belongs to the same container!
注意,std::vector没有remove member函数,这就是为什么要应用这个习惯用法。您可以阅读其中更详细的讨论。C++是一种标准,它不需要迭代器知道它属于什么容器。我们不能仅仅因为在一个特定的实现中,函数可以在不需要特定参数的情况下完成其工作而更改标准。C++是一个不需要迭代器的标准,它不需要知道它属于什么容器。我们不能改变标准,仅仅因为在一个特定的实现中,一个函数可以在不需要特定参数的情况下完成它的工作。 < P>其他提到,根据C++标准,这会导致未定义的行为。 但是,双链接列表的优点在于,从列表中删除节点只需要指向该节点的指针,而无需引用容器本身,例如:
template<class Tag>
inline void unlink(ListNode<Tag>* node)
{
ListNode<Tag> *prev = node->prev_, *next = node->next_;
prev->next_ = next;
next->prev_ = prev;
node->prev_ = node;
node->next_ = node;
}
您的代码工作正常,因为std::list通常被实现为一个双链接列表,而list::erase从迭代器中获取指向列表节点的指针,并执行与上述类似的代码。如果您启用了对迭代器的调试支持,此代码可能会导致运行时断言。 < P>其他提到,根据C++标准,这会导致未定义的行为。 但是,双链接列表的优点在于,从列表中删除节点只需要指向该节点的指针,而无需引用容器本身,例如:
template<class Tag>
inline void unlink(ListNode<Tag>* node)
{
ListNode<Tag> *prev = node->prev_, *next = node->next_;
prev->next_ = next;
next->prev_ = prev;
node->prev_ = node;
node->next_ = node;
}
您的代码工作正常,因为std::list通常被实现为一个双链接列表,而list::erase从迭代器中获取指向列表节点的指针,并执行与上述类似的代码。但是,如果启用迭代器的调试支持,此代码可能会导致运行时断言。如果std::list::erase实际上不需要了解这方面的知识,则这只是一个实现细节。它是一个成员函数,用于与其他容器保持一致。实际上,您可以将容器作为模板参数,并调用container.eraseiter 如果std::list::erase实际上不需要了解这方面的知识,那么这只是一个实现细节。它是一个成员函数,用于与其他容器保持一致。实际上,您可以将容器作为模板参数,并调用container.eraseiter 那么如何测试迭代器是否在容器的范围内呢。在本例中,b.开始=a、 end并不意味着b.begin是a的有效迭代器。@zer0ne:我想,你不能可靠地知道这一点。你需要以一种一开始就不需要的方式来编程,
那么我如何测试迭代器是否在容器的范围内呢。在本例中,b.开始=a、 end并不意味着b.begin是a的有效迭代器。@zer0ne:我想,你不能可靠地知道这一点。您需要以一种一开始就不需要的方式对其进行编程。@zerOne:查看我的更新答案。谢谢。当我得到更多的分数时,我会回来投票。@zerOne:看我更新的答案。谢谢。当我得到更多的分数时,我会回来投票。