gpt4 book ai didi

c++ - std::remove 与 vector::erase 和未定义的行为

转载 作者:IT老高 更新时间:2023-10-28 12:45:36 40 4
gpt4 key购买 nike

在整个网络上,我看到人们使用 erase/remove idiom对于像这样的 C++ vector :

#include <vector> // the general-purpose vector container
#include <iostream>
#include <algorithm> // remove and remove_if
int main()
{
// initialises a vector that holds the numbers from 0-9.
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// removes all elements with the value 5
v.erase( std::remove( v.begin(), v.end(), 5 ), v.end() );

return 0;
}

也就是说,如果我想删除所有符合某些条件的元素(例如 ints vector 中的数字 5),那么我使用 std::removestd::remove_ifvector.erase 一起使用,如下所示:

vector.erase( std::remove( vector.begin(), vector.end(), <some_value>), vector.end());

总的来说,这很好用; std::remove(和 remove_if)将复制(或在 C++11 中使用移动语义)要删除的元素到 vector 的末尾,所以我们之前示例中的 vector 现在看起来像这样:

{ 0, 1, 2, 3, 4, 6, 7, 8, 9, 5 };

元素 5 加粗,因为它已移到末尾。

现在,std::remove 将返回一个迭代器,然后我们在 erase 中使用它来清除元素。不错。

但是下面的例子呢?

int main()
{
// initialises an empty vector.
std::vector<int> v = {};

// removes all elements with the value 5
v.erase( std::remove( v.begin(), v.end(), 5 ), v.end() );

return 0;
}

这似乎在我运行它的所有平台上都按预期工作(不删除任何内容,不进行段错误等),但我知道仅仅因为某些东西在工作,并不意味着它不是未定义的行为。

快速 reference对于 vector.erase 这么说(强调我的):

iterator erase (const_iterator first, const_iterator last);

第一个,最后一个

Iterators specifying a range within the vector] to be removed: [first,last). i.e., the range includes all the elements between first and last, including the element pointed by first but not the one pointed by last. Member types iterator and const_iterator are random access iterator types that point to elements.

vector.erase(vector.end(),vector.end()) 是未定义的行为吗?

以下是快速引用中关于异常安全的内容:

If the removed elements include the last element in the container, no exceptions are thrown (no-throw guarantee). Otherwise, the container is guaranteed to end in a valid state (basic guarantee). An invalid position or range causes undefined behavior.

所以,至少在我看来,答案是"is",this StackOverflow answer似乎支持它。

所以,习语有错吗?

假设它是未定义的行为,那么任何对 remove 的调用都可以返回一个迭代器到 vector.end() 应该在调用 vector.erase,并且在空 vector 上调用 remove 似乎确实返回 vector.end: (IDEOne for code below)

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main() {
vector<int> myInts;
auto anIter = std::remove(myInts.begin(),myInts.end(),5);
if (anIter == myInts.end())
std::cout << "iterator = myInts.end()";
}

最后,我的问题:

实际的删除/删除习语应该是这样吗?

auto endOfRangeIterator = std::remove(vector.begin(), vector.end(), <value>);
if (endOfRangeIterator != vector.end())
vector.erase(endOfRangeIterator, vector.end())

最佳答案

24.2.1/7 Most of the library’s algorithmic templates that operate on data structures have interfaces that use ranges. A range is a pair of iterators that designate the beginning and end of the computation. A range [i,i) is an empty range; in general, a range [i,j) refers to the elements in the data structure starting with the element pointed to by i and up to but not including the element pointed to by j.

强调我的。

此外,您引用的erase的描述不是标准中的规范文本。标准中有这样的说法(表 100):

a.erase(q1,q2)

Effects: Erases the elements in the range [q1, q2).

这并不要求 q1 是可取消引用的。如果 [q1, q2) 是空范围(根据 24.2.1/7),则范围内没有元素,因此不会删除任何元素。

关于c++ - std::remove 与 vector::erase 和未定义的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23761273/

40 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com