令人疑惑的 std::remove 算法
摘自《Effective STL》第32条
remove的声明:
template<class ForwardIterator, class T>
ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T& value);
如同所有的算法一样,remove 也需要一对迭代器来指定所要进行操作的元素区间。它并不接受容器作为参数,所以 remove 并不知道这些元素被存放在哪个容器中。并且,remove 也并不能从迭代器推知对应的容器和容器类型。
唯一可以从容器中删除元素的方法是调用容器的成员函数 erase (list有几个可以删除元素的成员函数,但是没有命名为 erase)。remove 算法并不知道它操作的元素的所在容器,所以不可能从容器中删除元素。
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm> using namespace std; int main()
{
vector<int> c = {,,,,,,,,,};
cout << "size : " << c.size() << endl; remove(c.begin(), c.end(), );
cout << "size : " << c.size() << endl; }
执行后显示:
size :
size :
使用 remove 后,容器中的元素并没有减少。
remove 到底做了什么?
简而言之,remove 移动了区间中的元素。其结果是,“需要被删除”的元素被移到了区间的尾部。它返回一个迭代器,指向第一个“需要被删除”的元素。
调用 remove 之前,c 的布局如下:

调用 remove 之后:
vector<int>::iterator newEnd(remove(c.begin(), c.end(), ));
c 的布局如下
你会发现最后两个元素的值没有发生变化。。。
这个是 remove 算法的附带结果。在内部,remove 遍历整个区间,用需要保留的元素的值覆盖掉那些要被删除的元素的值。这种覆盖是通过对那些需要被覆盖的元素的赋值来完成的。
因此,要想删除这些元素,必须调用区间形式的 erase。
还用两个类似的算法:remove_if 和 unique。都需要在调用 remove_if 和 unique 后调用 erase。
其中 list 的调用是不一致的,list::remove 会真正删除元素(并且比使用 erase-remove 习惯用法更加高效),list::unique 也会真正删除元素(并且比使用 erase-unique 更加高效)
注意:当容器中存放的是指向动态分配的对象的指针时,应该避免使用 remove 和类似的算法(remove_if 和 unique)。
可以使用智能指针。
令人疑惑的 std::remove 算法的更多相关文章
- 【翻译】std::remove - C++ Reference
函数模板 std::remove 头文件<algorithm> template <class ForwardIterator, class T> ForwardIterato ...
- JAVA中令人疑惑的字符串
Java中不同的字符串存在于同一个存储池中,字符串变量将指向存储池中相应的位置,也就是字符串变量里面包含的并不是字符串而是这个字符串对象的内存地址. String a = "123" ...
- C++ 标准库 std::remove
参见:https://zh.cppreference.com/w/cpp/algorithm/remove std::remove 不会改变输入vector / string 的长度.其过程,相当于去 ...
- std::remove
#include <algorithm> template< class ForwardIt, class T > ForwardIt remove( ForwardIt fi ...
- STL之算法使用简介
accumlate : iterator 对标志的序列中的元素之和,加到一个由 init 指定的初始值上.重载的版本不再做加法,而是传进来的二元操作符被应用到元素上. adjacent_differ ...
- 28.STL常用算法
#include <algorithm> 算法 常用版本 描述 返回Type std::find() find(_InIt _Fisrt,_InIt _Last, _Ty& _Va ...
- C++学习笔记-STL
C++ STL (Standard Template Library标准模板库) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues(队列), lists(链表), 和 ...
- STL源代码分析——STL算法remove删除算法
前言 因为在前文的<STL算法剖析>中,源代码剖析许多.不方便学习,也不方便以后复习,这里把这些算法进行归类.对他们单独的源代码剖析进行解说.本文介绍的STL算法中的remove删除算法. ...
- STL区间成员函数及区间算法总结
STL区间成员函数及区间算法总结 在这里总结下可替代循环的区间成员函数和区间算法: 相比单元素遍历操作,使用区间成员函数的优势在于: 1)更少的函数调用 2)更少的元素移动 3)更少的内存分配 在区间 ...
随机推荐
- struts2框架之类型转换(参考第二天学习笔记)
类型转换 1. 什么是类型转换 刚才学习了封装请求参数,把表单数据封装到Action(模型)的属性中.表单中的数据都是String类型,但Action(模型)的属性不一定什么类型. 将来我们还需要数据 ...
- struts2框架之请求参数(参考第二天学习笔记)
获取请求参数 请求参数:表单中的数据,或者是超链接中的数据. 1. 得到request,再通过request来获取.2. 属性驱动 在Action中提供与表单字段名称相同的属性即可. 而一个名为par ...
- 运维与自动化系列③自动化部署基础与shell脚本实现
自动化部署基础与shell脚本实现 关于自动化的基础知识: 1.1:当前代码部署的实现方式: 运维纯手工scp到web服务器纯手工登录git服务器执行git pull或svn服务器执行svn upda ...
- Jenkins pipeline概念理解
1.Jenkins Pipeline总体介绍 Pipeline,简而言之,就是一台运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程 ...
- Gradle缓存目录文件命名规则
在打开Android Studio项目的时候,会下载项目对应版本的gradle,该版本是在项目根目录下\gradle\wrapper\gradle-wrapper.properties文件中指定的: ...
- PyJWT 使用
最近要用 Falsk 开发一个大点的后端,为了安全考虑,弃用传统的Cookie验证.转用JWT. 其实 Falsk 有一个 Falsk-JWT 但是我觉得封装的太高,还是喜欢通用的 PyJWT . J ...
- JsRender 前端渲染模板基础学习
JsRender前端渲染模板 使用模板,可以预先自定义一些固定格式的HTML标签,在需要显示数据时,再传入真实数据组装并展示在Web页中:避免了在JS中通过“+”等手动分割.连接字符串的复杂过程:针对 ...
- JAVA框架之Hibernate框架的学习步骤
首先介绍一下Java三大框架的关系 以CRM项目即客户关系管理项目示例 hibernate框架的学习路线: 1.学习框架入门,自己搭建框架,完成增删改查的操作 2.学习一级缓存,事物管理和基本查询 3 ...
- 整理oracle 树形查询
注:本文参考了<整理oracle 树形查询> sql树形递归查询是数据库查询的一种特殊情形,也是组织结构.行政区划查询的一种最常用的的情形之一.下面对该种查询进行一些总结: create ...
- Confluence 6 白名单允许进入和禁用
允许进入 启用 CORS 请求,将会从特定的 URL 来源中允许进入(Allow Incoming).URL 格式必须匹配格式 scheme://host[:port],结尾是没有反斜杠的(:port ...