erase
作用:删除内存擦除
简单的说,就是能够从内存中擦除掉你想删除的元素
函数原型:
(1)string& erase ( size_t pos = 0, size_t n = npos );
(2)iterator erase ( iterator position );
(3)iterator erase ( iterator first, iterator last );
earse(pos, npos) 删除从pos开始的npos个字符
比如 :earse(1, 3) 删除第二个到第四个字符
void test()
{
string s = "Hello World!";
//注意:这里面的参数类型都是size_t,也就是说只能放整数
//如果是 s.earse(s.begin(), 5)将会报错,因为s.begin()的类型不是size_t,而是iterator
s.erase(2, 5);
//如果没有给出npos,系统会自动删除pos后面的所有元素
s.erase(2);
}
结果:
Heorld!
He
erase(position) 删除position位置的元素
void test()
{
string s = "Hello World!";
//删除第三个位置的字符
//这个一定要和上面的s.erase(2)区分开,这两者里面的参数类型是不一样的
s.erase(s.begin() + 2);
cout << s << endl;
}
结果:Helo World!
erase(first, last) 删除从first开始last(不包含last)
void test()
{
string s = "Hello World!";
//一定要和s.earse(2, 5)区分开,两者所表示的含义不一样
s.erase(s.begin() + 2, s.end() - 1);
cout << s << endl;
}
结果:He!
earse所存在的坑
- 不能将 s.begin() 强转为int
- 当想要删除某一个字符时,需要先找到这个字符(find)
earse不存在通过字符将其删除的函数
void test()
{
string s = "Hello World!";
s.erase(find(s.begin(), s.end(), 'e'));
cout << s << endl;
}
结果:Hllo World!
- 链表容器使用erase删除节点会将下一个元素的地址返回
例如下面这个题:
删除所有的5
void test()
{
vector<int> v = { 4, 3, 2, 5, 5, 5, 5, 4, 3 };
vector<int>::iterator it;
for (it = v.begin(); it < v.end(); ++it)
{
if (*it == 5)
{
v.erase(it);
}
}
}
这个一编译就会报错,因为直接删除会导致迭代器失效(迭代器失效问题会在以后的博客中详细介绍)。因为 it 是个迭代器,可以把它理解为一个指针,把指针删除后(可以理解为野指针),又如何进行 ++ 操作?,故要将删除后的下一个元素位置保存起来。
void test()
{
vector<int> v = { 4, 3, 2, 5, 5, 5, 5, 4, 3 };
vector<int>::iterator it = v.begin();
while (it != v.end())
{
if (*it == 5)
{
//因为erase函数会返回删除元素的下一个元素的地址
it = v.erase(it);
}
else
{
++it;
}
}
}
结果:
remove
函数原型:
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);
简单的说,就是:
remove(first, last, val) 删除first到last之间所有值为val的元素
remove在STL中的源代码:
template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val)
{
ForwardIterator result = first;
while (first!=last) {
if (!(*first == val)) {
*result = move(*first);
++result;
}
++first;
}
return result;
}
对vector来说
remove只是通过迭代器的指针向后移动来删除,将没有被删除的元素放在链表的前面,并返回一个指向新的位置的迭代器。由于remove()函数不是vector成员函数,因此不能调整vector容器的长度。(对vector来说)remove()函数并不是真正的删除,要想真正删除元素则可以使用erase()或者resize()函数。
对于下面的代码:
void test()
{
vector<char> v;
vector<char>::iterator ret;
v.push_back('q');
v.push_back('w');
v.push_back('e');
v.push_back('r');
v.push_back('b');
v.push_back('w');
v.push_back('w');
remove(v.begin(), v.end(), 'w');
}
结果:
里面的 ‘w’ 并没有被全部删除,为什么会有这种情况?
所以,要通过remove删除元素,就要借助earse
void test()
{
vector<char> v;
vector<char>::iterator ret;
v.push_back('q');
v.push_back('w');
v.push_back('e');
v.push_back('r');
v.push_back('b');
v.push_back('w');
v.push_back('w');
v.erase(remove(v.begin(), v.end(), 'w'), v.end());
}
结果:
对于list来说
remove()函数作为列表list容器的成员函数,可以从列表容器中删除与x相等的元素,同时会减小列表容器的大小,其减小的数量等于被删除的元素的个数
原型:
remove(const T& val)
void test()
{
list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(3);
l.push_back(4);
l.push_back(5);
l.push_back(3);
l.remove(3);
}
这次就不用借助erase函数,就可将其全部删除
结果:
remove_if
函数原型:ForwardIterator remove_if (ForwardIterator first, ForwardIterator last,
UnaryPredicate pred);
简单的说就是:remove_if(first, last, pred) 从first到last中将满足条件pred的元素删除
这个函数就是按条件删除元素
对于vector而言
remove_if的参数是迭代器,通过迭代器无法得到容器本身,而要删除容器内的元素只能通过容器的成员函 数来进行,因此remove系列函数无法真正删除元素,只能把要删除的元素移到容器末尾并返回要被删除元素的迭代器,然后通过erase成员函数来真正删除。
bool IfEqualThree(int ret)
{
return ret == 3;
}
void test()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(3);
v.erase(remove_if(v.begin(), v.end(), IfEqualThree), v.end());
}
结果:
对于list而言
因为remove_if是list的成员函数,可以直接删除元素
void test()
{
list<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(3);
v.remove_if(IfEqualThree);
}
结果: