Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 删除外部迭代器_C++_Iterator_Erase - Fatal编程技术网

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:看我更新的答案。谢谢。当我得到更多的分数时,我会回来投票。