Effective STL 条款37

Effective C++ 第三版 所有条款总结及对应代码描述(纯干货) Effective C++ 第三版 所有条款总结及对应代码描述(纯干货) 阅读详情

条款37:用accumulate或for_each来统计区间

有时候你需要把整个区间提炼成一个单独的数,或,更一般地,一个单独的对象。对于一般需要的信息,有特殊目的的算法来完成这个任务,比如,count告诉你区间中有多少元素,而count_if告诉你有多少元素满足一个判断式。区间中的最小和最大值可以通过min_element和max_element获得。

但有时,你需要用一些自定义的方式统计(summarize)区间,而且在那些情况中,你需要比count、count_if、min_element或max_element更灵活的东西。比如,你可能想要对一个容器中的字符串长度求和。你可能想要数的区间的乘积。你可能想要point区间的平均坐标。在那些情况中,你需要统计一个区间,但你需要有定义你需要统计的东西的能力。没问题。STL为你准备了那样的算法,它叫作accumulate。你可能不熟悉accumulate,因为,不像大部分算法,它不存在于<algorithm>。取而代之的是,它和其他三个“数值算法”都在<numeric>中。(那三个其它的算法是inner_product、adjacent_difference和partial_sum。)

就像很多算法,accumulate存在两种形式。带有一对迭代器和初始值的形式可以返回初始值加由迭代器划分出的区间中值的和:

list<double> Id;      // 建立一个list,放
...       // 一些double进去
double sum = accumulate(ld.begin(), Id.end(), 0.0);  // 计算它们的和,
       // 从0.0开始

在本例中,注意初始值指定为0.0,不是简单的0。这很重要。0.0的类型是double,所以accumulate内部使用了一个double类型的变量来存储计算的和。如果这么写这个调用:

double sum = accumulate(ld.begin(), Id.end(), 0);  // 计算它们的和,
       // 从0开始;
       // 这不正确!

如果初始值是int 0,所以accumulate内部就会使用一个int来保存它计算的值。那个int最后变成accumulate的返回值,而且它用来初始化和变量。这代码可以编译和运行,但和的值可能不对。不是保存真的double的list的和,它可能保存了所有的double加起来的结果,但每次加法后把结果转换为一个int。

accumulate只需要输入迭代器,所以你甚至可以使用istream_iterator和istreambuf_iterator(参见条款29):

cout << "The sum of the ints on the standard input is"  // 打印cin中
  << accumulate(istream_iterator<int>(cin), // 那些int的和
    istream_iterator<int>(),
    0);

进行数值算法是accumulate的默认行为。但当使用accumulate的另一种形式,带有一个初始和值与一个任意的统计函数,这变得一般很多。

比如,考虑怎么使用accumulate来计算容器中的字符串的长度和。要计算这个和,accumulate需要知道两个东西。第一,同上,它必须知道和的开始。在我们的例子中,它是0。第二,它必须知道每次看到一个新的字符串时怎么更新这个和。要完成这个任务,我们写一个函数,它带有目前的和与新的字符串,而且返回更新的和:

string::size_type     // string::size_type的内容
stringLengthSum(string::size_type sumSoFar,  // 请看下文
   const string& s)
{
 return sumSoFar + s.size();
}

这个函数的函数体非常简单,但你可能发现自己陷于string::size_type的出现。不要那样。每个标准STL容器都有一个typedef叫做size_type,那是容器计量东西的类型。比如,这是容器的size函数的返回类型。对于所有的标准容器,size_type必须是size_t,但理论上非标准STL兼容的容器可能让size_type使用一个不同的类型(虽然我花了很多时间来想为什么它们要那么做)。对于标准容器,你可以把Container::size_type看作size_t写法的一个奇异方式。

stringLengthSum是accmulate使用的统计函数的代表。它带有到目前为止区间的统计值和区间的下一个元素,它返回新的统计值。一般来说,那意味着函数会带不同类型的参数。那就是这里所做的。到目前为止的统计值(已经看到的字符串的长度和)是string::size_type类型,而要检查的元素的类型是string。典型地在这个例子中,这里的返回类型和函数的第一个参数相同,因为它是更新了的统计值(加上了最后计算的元素)。

我们可以让accumulate这么使用stringLengthSum:

set<string> ss;     // 建立字符串的容器,
...      // 进行一些操作
string::size_type lengthSum =   // 把lengthSum设为对
 accumulate(ss.begin(), ss.end(),  // ss中的每个元素调用
   0, stringLengthSum); // stringLengthSum的结果,使用0
      // 作为初始统计值

很好,不是吗?计算数值区间的积甚至更简单,因为我们不用写自己的求和函数。我们可以使用标准multiplies仿函数类:

vector<float> vf;     // 建立float的容器
...      // 进行一些操作
float product =     // 把product设为对vf
 accumulate(vf.begin(), vf.end(),  // 中的每个元素调用
   1.0, multiplies<float>()); // multiplies<float>的结果,用1.0
      // 作为初始统计值

这里唯一需要小心的东西是记得把1(作为浮点数,不是int!)作为初始统计值,而不是0。如果我们使用0作为开始值,结果会总是0,因为0乘以任何东西也是0,不是吗?

我们的最后一个例子有一些晦涩。它完成寻找point的区间的平均值,point看起来像这样:

struct Point {
 Point(double initX, double initY): x(initX), y(initY) {}
 double x, y;
};

求和函数应该是一个叫做PointAverage的仿函数类的对象,但在我们察看PointAverage之前,让我们看看它在调用accumulate中的使用方法:

list<Point> Ip;
...
Point avg =     // 对Ip中的point求平均值
 accumulate(lp.begin(), lp.end(),
   Point(0, 0), PointAverage());

简单而直接,我们最喜欢的方式。在这个例子中,初始和值是在原点的point对象,我们需要记得的是当计算区间的平均值时不要考虑那个点。

PointAverage通过记录它看到的point的个数和它们x和y部分的和的来工作。每次调用时,它更新那些值并返回目前检查过的point的平均坐标,因为它对于区间中的每个点只调用一次,它把x与y的和除以区间中的point的个数,忽略传给accumulate的初始point值,它就应该是这样:

class PointAverage:
  public binary_function<Point, Point, Point> {  // 参见条款40
public:
 PointAverage(): xSum(0), ySum(0), numPoints(0) {}
 const Point operator()(const Point& avgSoFar, const Point& p) {
  ++numPoints;
  xSum += p.x;
  ySum += p.y;
  return Point(xSum/numPoints, ySum/numPoints);
 }
private:
 size_t numPoints;
 double xSum;
 double ySum;
};

这工作得很好,而且仅因为我有时候和一些非常狂热的人打交道(他们中的很多都在标准委员会),所以我才会预见到它可能失败的STL实现。不过,PointAverage和标准的第26.4.1节第2段冲突,我知道你想起来了,那就是禁止传给accumulate的函数中有副作用。成员变量numPoints、xSum和ySum的修改造成了一个副作用,所以,技术上讲,我刚展示的代码会导致结果未定义。实际上,很难想象它无法工作,但当我这么写时我被险恶的语言律师包围着,所以我别无选择,只能在这个问题上写出难懂的条文。

那很好,因为它给我了一个机会来提起for_each,另一个可以用于统计区间而且没有accumulate那么多限制的算法。正如accumulate,for_each带有一个区间和一个函数(一般是一个函数对象)来调用区间中的每个元素,但传给for_each的函数只接收一个参数(当前的区间元素),而且当完成时for_each返回它的函数。(实际上,它返回它的函数的一个拷贝——参见条款38。)值得注意的是,传给(而且后来要返回)for_each的函数可能有副作用。

除了副作用问题,for_each和accumulate的不同主要在两个方面。首先,accumulate的名字表示它是一个产生区间统计的算法,for_each听起来好像你只是要对区间的每个元素进行一些操作,而且,当然,那是那个算法的主要应用。用for_each来统计一个区间是合法的,但是它没有accumulate清楚。

其次,accumulate直接返回那些我们想要的统计值,而for_each返回一个函数对象,我们必须从这个对象中提取想要的统计信息。在C++里,那意味着我们必须给仿函数类添加一个成员函数,让我们找回我们追求的统计信息。

这又是最后一个例子,这次使用for_each而不是accumulate:

struct Point {...);     // 同上
class PointAverage:
  public unary_function<Point, void> {  // 参见条款40
public:
 PointAverage(): xSum(0), ySum(0), numPoints(0) {}
 void operator()(const Point& p)
 {
  ++numPoints;
  xSum += p.x;
  ySum += p.y;
 }
 Point result() const
 {
  return Point(xSum/numPoints, ySum/numPoints);
 }
private:
 size_t numPoints;
 double xSum;
 double ySum;
};
list<Point> Ip;
...
Point avg = for_each(lp.begin(), lp.end(), PointAverage()).result;

就个人来说,我更喜欢用accumulate来统计,因为我认为它最清楚地表达了正在做什么,但是for_each也可以,而且不像accumulate,副作用的问题并不跟随for_each。两个算法都能用来统计区间。使用最适合你的那个。

你可能想知道为什么for_each的函数参数允许有副作用,而accumulate不允许。这是一个刺向STL心脏的探针问题。唉,尊敬的读者,有一些秘密总是在我们的知识范围之外。为什么accumulate和for_each之间有差别?我也希望听到一个令人信服的解释。

【绝版C++书籍】《Effective STL》读书笔记 《Effective STL》读书笔记写在前面《Effective STL》中可能过时的内容1 容器第1条:慎重选择容器类型。第2条:不要试图编写独立于容器类型的代码。第3条:确保容器中的对象拷贝正确而高效。第4条:调用empty而不是检查size()是否为0。第5条:区间成员函数优先于与之对应的单元素成员函数。第6条:当心C++编译器最烦人的分析机制。第7条:如果入容器中包含了通过new操作创建的指针,切记在容器对象析构前将delete掉。第8条:切勿创建包含auto_ptr的容器对象。第9条:慎重选择删 阅读详情

相关推荐

SAP PP模块 MRP配置实战:5步完成工厂级物料需求计划激活

本文详细介绍了SAP PP模块中物料需求计划(MRP)的工厂级配置实战,通过5个关键步骤从基础环境准备到最终激活。内容涵盖SPRO后台配置、MRP控制者定义、主数据设置及核心参数调整,帮助顾问快速掌握MRP配置清单的完整流程,确保物料需求计划的高效运行。

weixin_30431445的博客 340

37. 使用accumulate或者for_each进行区间统计

accumulate和for_each在两个方面有所不同。 名字accumulate暗示着这个算法将会计算出一个区间的统计信息。而for_each听起来就好像是对一个区间的每个元素做一个操作,用for_each来统计一个区间是合法的,但是不如accumulate来得清晰。 accumulate直接返回我们索要的统计结果,而for_each却返回一个函数对象,我们必须从这个函数对象中提取出我...

xupeng1644的博客 1602

C++容器使用经验总结

第1章 容器 第1条:慎重选择容器类型。 标准STL序列容器:vector、string、deque和list。 标准STL关联容器:set、multiset、map和multimap。 非标准序列容器slist和rope。slist是一个单向链表,rope本质上是一“重型”string。 非标准的关联容器hash_set、hase_multiset、hash_m

小憩一下 591

某教育平台线上用户流失分析

本项目基于某教育平台的用户登录信息、用户个人信息以及用户课程学习记录三信息表,挖掘了平台流量以及用户流失等信息。使用python对数据进行预处理,使用tableau进行数据可视化分析。该教育平台正值窗口期,平台流量没有良好的留存水平,但有良好的发展趋势,需要深入分析用户留存率低,做好招新促活营销。该教育平台的基本盘在广东、湖北、河南、贵州等省份,线上教育的潜在用户可能更多分布在线下教育资源不充足、受疫情影响更为严重的地区。

fhy12的博客 1299

基于紫光同创FPGA的adf网表文件使用和黑匣子设置

这个时候就可以选择将你的网表文件给到他使用,就是相当于把你的功能模块封装成了一个黑匣子一样,只有外部端口,没有内部代码;,在TOP层的子模块声明里面需要加上/*synthesis syn_black_box */进行黑匣子设置,此时子层 adf 文件作为黑盒是不会综合的,在 device map 时会将顶层综合结果与子层 adf 文件合并传递至布局布线阶段;这些都设置完毕后呢,就可以对工程进行编译和综合了,综合完毕后会生成一个.adf的网表文件,我们要使用的就是这个文件;我这里是把两个子模块的添加了哈;

H2061722的博客 964

Effective STL学习笔记-条款37

用accumulate或for_each来统计区间一般的统计算法可以使用count和count_if来替代,他们告诉你某个区间有多少等于某个值的元素。 而accumulate和for_each是对于区间的的统计。accumulate看个简单例子: list<double> ld = { 0.0, 0.1, 1.1, 2.2, 3.0 }; double sum = std::accu

柠檬柠檬C的博客 356

Android CCodec (四) Output Buffer流程分析

Android 多媒体架构 Codec2 Output Buffer

给大佬递杯卡布奇诺的博客 3264

Effective STL 中文版(大全)

候捷说,对于STL,程序员有三个境界,开始是使用STL,然后是理解STL,最后是补充STL。EffectiveSTL是一本非常好的书,帮助你更好的理解STL,其作者就是《EffectiveC++》一书的作者。如果你已经初步了解了STL的容器、迭代器、算法和函数,而又想更好的了解STL,那么《EffectiveSTL》是你的最佳选择。 还有一部分没有找到链接,如果再找不到我会自己试着翻译

幸福村的人 1139

A Macro- and Micro-Hierarchical Transfer Learning Frameworkfor Cross-Domain Fake News Detection

近年来,社交媒体上假新闻的快速和广泛传播对人们的日常生活构成了越来越大的威胁[6, 14, 19]。为了有效打击假新闻,自动检测假新闻变得至关重要[39]。新闻内容[11, 16, 20, 27]和用户互动(即用户互动)[1, 24, 34]。基于这些类型的数据,提出了单领域假新闻检测,它从新闻文章、用户互动或两者中提取有效特征,以识别单个新闻领域内新闻的真实性(即新闻是真是假)(例如,政治新闻或娱乐新闻)。

qq_52053775的博客 155

科研级YOLOv8 Neck革新:BiFPN双向特征金字塔赋能,让多尺度融合更高效的实战指南

在文件夹下新建BiFPN.py,将上述BiFPNLayer和BiFPN类的代码写入其中。这一步是为了让YOLOv8的代码架构能识别我们的自定义Neck模块。

m0_64661770的博客 152

2 Studying《Effective STL》

《Effective STL》摘要 STL是C++标准库的重要组成部分,涵盖容器、迭代器、算法和函数对象等。本文总结了STL使用中的关键要点: 容器选择: 根据插入删除位置选择序列容器(vector、list、deque) 考虑查找效率选择关联容器(set、map)或哈希容器 指针容器需注意资源管理,建议使用智能指针 容器操作优化: 优先使用empty()而非size()==0 区间操作比单元素操作更高效 使用reserve避免频繁重新分配内存 注意string实现的多样性 算法使用: 确保目标区间足够大

u012906122的专栏 753

OpenAI最强编程助手Codex:下载安装、使用指南(含使用方式、提示技巧、趋势)

OpenAI最近上线了最强编程Agent——Codex,一起来看看吧!

Code_流苏:在代码中寻诗意,在实践中觅真知 1万+

Effective STL 条款48

条款48:总是#include适当的头文件STL编程的次要麻烦之一是虽然可以很容易地建立可以在一个平台上编译的软件,但在其它平台上则需要附加的#include指示。这个烦恼来自一个事实:C++标准(不像C标准)未能指定哪一个标准头文件必须或者可能被其他标准头文件#include。由于有了这样的灵活性,不同的实现就会选择去做不同的东西。 这在实践中意味着什么?我可以给你一些的概念。我使用了五

AMin2001的专栏 1334

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Effective STL 目录

由于没有看内容,有些翻译可能不准确,请见谅:)容器条款1: 仔细选择你要的容器 条款2: 小心对“容器无关代码”的幻想 条款3: 使容器里对象的拷贝操作轻量而正确 条款4: 用empty来代替检查size是否为0 条款5: 尽量使用范围成员函数代替他们的单元素兄弟 条款6: 警惕C++的及其令人恼怒的分析 条款7: 当使用new得指针的容器时,切记在容器销毁前d

AMin2001的专栏 1483

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Effective STL目录

    从去年12月开始,我花了40天看了《Effective STL》这本书,并写了相关的读书笔记,我在考虑是否将这部分笔记在BLOG上贴出来。在此之前,先贴上Effective STL目录,并且强烈推荐这本书。如果想加深对STL的了解,这本书必不可少。同时还需要参考的书是《STL源代码剖析》。这篇目录上带有了相关链接。前言致谢导读容器条款1:仔细选择你的容器条款2:小心对“容器无关代码”的幻想

李永亮的专栏 1861

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Effective C++ 条款总结

Effective C++ 条款总结一、让自己习惯C++1 视C++为一个语言联邦2 尽量使用const等替换#define3 尽可能使用const4 确定对象使用前被初始化 自己在看这本书的时候,回去翻看目录的时候,有些规则会被遗忘,因此做个简单的小总结供自己和其他人参考,没读过的还是要先去读一遍的 一、让自己习惯C++ 1 视C++为一个语言联邦 C++是一种包含许多特性的语言,因而不要把它视为一个单一语言。理解C++至少需要学习一下4个部分: C语言。C++仍以C为基础 objected-ori

catkin_ws的博客 1177

【C++】万字详解Effective C++

本文为前段时间读《Effective C++》(侯捷译)时做的个人笔记。

Friday 4289

【一文读懂】《Effective STL》50条有效使用STL的经验

本文按 Scott Meyers《Effective STL》(2001)原书 8 章顺序,系统梳理全部 50 条条款,覆盖容器选型、vector/string、关联容器、迭代器、算法、函数子、STL 实战与其他议题。对初学者易混淆处配代码示例,并在关键处标注 C++11/20 的现代等价写法(如 unordered_map、std::erase_if、lambda 取代 bind1st)。

码工许师傅 366

Effective STL笔记

#estl 第50条:熟悉与STL相关的web站点。三个:www.sgi.com/tech/stl、www.stlport.org 和 www.boost.org。 #estl 第49条:学会分析与STL相关的编译器诊断信息。嗯,第一招是替换大法,然后介绍了一下与容器、插入迭代器、绑定器、输出迭代器或算法相关的错误大概有什么套路看。 #estl 第48条:总是包含(#include)正确 的头文件...

weixin_34015566的博客 164

「经典研读」Effective STL

研读 Effective STL 时的一些心得和记录,不一定正确,请酌情参考,从容器、迭代器和算法等几个方面展开

士全的优快云,用心连载,欢迎关注 482

Effective STL 中文版(完整版)

Winter总算找到《Effective STL》的完整中文版了,奉献给大家。书中作者解释了怎样结合STL组件来在库的设计得到最大的好处。这样的信息允许你对简单、直接的问题开发简单、直接的解决方案,也帮你对更复杂的问题设计优雅的方法。我描述了常见的STL使用错误,而且向你演示怎么避开它们。那帮助你躲开闪资源漏、不可移植的代码和未定义的行为。我讨论了优化代码的方法,所以你能使STL表现得像它应该的那

sdnxiaotao的专栏 1473
上一篇: Effective STL 条款35
下一篇: Effective STL条款50
AMin2001
博客等级 码龄26年 7粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值