std::remove with vector::erase和未定义行为 在整个Web上我看到人们使用的是C++向量,如: #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; }
这在一般情况下效果很好std::remove with vector::erase和未定义行为 在整个Web上我看到人们使用的是C++向量,如: #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; },c++,algorithm,c++11,vector,stl,C++,Algorithm,C++11,Vector,Stl,这在一般情况下效果很好std::remove(和remove\u if)会将要删除的元素复制(或在C++11中使用移动语义)到向量的末尾,因此我们前面示例中的向量现在如下所示: {0,1,2,3,4,6,7,8,9,5} 元素5加粗,因为它已移动到末尾 现在,std::remove将返回一个迭代器,然后在erase中使用该迭代器清除元素。很好 但是下面的例子呢? 第一个、最后一个是 迭代器指定要删除的向量]内的范围:[first,last)。即,范围包括first和last之间的所有元素,包括f
std::remove
(和remove\u if
)会将要删除的元素复制(或在C++11中使用移动语义)到向量的末尾,因此我们前面示例中的向量现在如下所示:
{0,1,2,3,4,6,7,8,9,5}
元素5加粗,因为它已移动到末尾
现在,std::remove
将返回一个迭代器,然后在erase
中使用该迭代器清除元素。很好
但是下面的例子呢?
第一个、最后一个是
迭代器指定要删除的向量]内的范围:[first,last)
。即,范围包括first
和last
之间的所有元素,包括first指向的元素,但不包括last
指向的元素。
成员类型iterator
和const_iterator
是指向元素的随机访问迭代器类型
vector.erase(vector.end(),vector.end())
未定义的行为也是如此?
以下是《快速参考》中有关异常安全的内容:
如果删除的元素包括容器中的最后一个元素,则不会抛出异常(无抛出保证)。
否则,将保证容器以有效状态结束(基本保证)。
无效的位置
或范围
会导致未定义的行为
所以,答案,至少在我看来是“是的”,并且似乎支持它
因此,常见的习语是错误的吗?
假设它是未定义的行为,那么对remove
的任何调用都可能返回到vector.end()
的迭代器,在调用vector.erase
之前应该检查迭代器,对空向量调用remove似乎返回vector.end
:()
#包括
#包括
#包括
使用名称空间std;
int main(){
媒介粘虫;
auto anIter=std::remove(myInts.begin(),myInts.end(),5);
if(anIter==myInts.end())
标准::cout
vector.erase(vector.end(),vector.end())的行为是否未定义
不,因为你的演讲旁边有一句话:
迭代器指定要删除的向量]内的范围:[first,last]。即,该范围包括first和last之间的所有元素,包括first指向的元素,但不包括last指向的元素
因此,vector.erase(vector.end(),vector.end())
不会尝试擦除vector.end()
,因为它是由参数last
指向的
诚然,这一定义是含糊不清的,这些陈述可能被解释为相互矛盾的。本标准未使用引用的措辞
24.2.1/7大多数在数据结构上运行的库算法模板都有使用范围的接口。范围是一对
指定计算开始和结束的迭代器的名称。
范围[i,i)
是一个空范围;通常,范围[i,j)
指数据结构中以元素开头的元素
由i
指向,但不包括指向的元素
通过j
我的
此外,您引用的erase
说明不是本标准中的规范性文本。本标准规定(表100):
a.擦除(q1,q2)
效果:擦除[q1,q2]范围内的元素
这并不要求q1
是可取消引用的。如果[q1,q2]是一个空范围(根据24.2.1/7),那么该范围内没有元素,因此没有任何元素被删除。我认为在您的引用中更重要的是:
迭代器指定要删除的向量]内的范围:
[第一个,最后一个)。即,范围包括第一个和第二个之间的所有元素
最后,包括第一个指向的元素,但不包括第一个指向的元素
由last指向。成员类型迭代器和常量迭代器是随机的
访问指向元素的迭代器类型
正如我们在评论中所发现的,此引用是不正确的。在(v.end,v.end)
的情况下,这不会违反规则,但在
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3 };
v.erase( v.begin(), v.begin());
}
#包括
int main()
{
向量v={1,2,3};
v、 擦除(v.begin(),v.begin());
}
因为这句话与
范围包括(…),包括所指的元素
v、 begin()但不是v.begin()所指的那一个
不能是有效的语句
§23.2.2序列容器要求表100中的C++标准n3337规定
a.erase(q1,q2)
返回iterator
。注意:
要求:对于vector和deque,T应是可移动和可分配的。效果:
擦除[q1,q2]范围内的元素。
这就是它在§24.2.1/7迭代器要求中对范围[i,j)
的说明
库中大多数对数据进行操作的算法模板
结构具有使用范围的接口。范围是一对
指定计算开始和结束的迭代器。A
范围[i,i)是一个空范围;通常,范围[i,j]指的是
数据结构中以
i和之前,但不包括j所指的元素。范围[i,j)
当且仅当j可从i到达时有效
无法将库中的函数应用于无效范围
未定义
这样就可以回答你的问题了
但是下面的例子呢
cplusplus.com是
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;
}
iterator erase (const_iterator first, const_iterator last);
#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())
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3 };
v.erase( v.begin(), v.begin());
}