[译]GotW #3: Using the Standard Library (or, Temporaries Revisited)
高效的代码重用是良好的软件工程中重要的一部分。为了演示如何更好地通过使用标准库算法而不是手工编写,我们再次考虑先前的问题。演示通过简单利用标准库中已有的算法来避免的一些问题。
Problem
JG Question
1. 最广泛使用的C++库是什么?
Guru Question
2. 首先,在GotW #2中有多少陷进是可以避免的,如果程序员只是用以下方法替代显示的基于迭代器的for循环:
(a)一个基于范围的for循环?
(b)一个标准库算法调用?
(注意:和GotW #2一样,不要改变函数的语义,即使它们有些地方是可以改进的)
为了简单说明,下面是大部分都已经修正了的函数:
string find_addr( const list<employee>& emps, const string& name ) {
for( auto i = begin(emps); i != end(emps); ++i ) {
if( i->name() == name ) {
return i->addr;
}
}
return "";
}
Solution
1. 最广泛使用的C++库是什么?
在每个平台上的实现的C++标准库。
2. (a)使用基于范围的for循环可以避免多少GotW #2中的陷进?
在GotW #2中,机灵的读者可能会说:“为什么你不使用基于范围的for循环?”的确,为什么不?它还会解决一些临时对象问题,不要介意它写的那么简单。
比较先前没有改进的显示迭代器循环:
for( auto i = begin(emps); i != end(emps); i++ ) {
if( *i == name ) {
return i->addr;
}
}
和使用基于范围的for循环(如果你记得写上const auto&还会加分)
for( const auto& e : emps ) {
if( e == name ) {
return e.addr;
}
}
表达式e==name和return e.addr在可能会在实际的临时对象方面都没有变化。但是裸循环代码中的不论是=引发的临时对象(回想一下:它没有),还是end()重新计算且应该保存在循环外(回想一下:可能不会,但也许),还是i++应该被重写成++i(回想一下:它应该这么做),这些问题在基于范围的循环中都得到了解决。这就是清晰代码的能力,同时使用了更高的抽象。
使用基于范围的for循环的关键优点是增了代码的抽象层次和信息密度。考虑一下:下面两行代码中,在不继续阅读接下来的代码时,你能想到什么:
for( auto i = begin(emps); i != end(emps); i++ ) { // A
for( const auto& e : emps ) { // B
乍看起来,A行和B行都传达了相同的信息,但却不是这样。当看到A行时,你所知道的所有就是那是个循环,使用迭代器迭代了emps。我们如此习惯于于A,以致于我们眼睛次要的视觉都趋于在我们脑子里将它“自动补全”为“一个顺寻访问emps元素的循环”,且我们的自动补全通常是对的,除了当它不是:那是个++还是s+=2的循环步幅?在循环体内索引被修改了?我们次要的视觉可能会出错。
另一方面,B行传达了更多的信息给读者。当你看到B行时,在没有检查循环体的情况下你能确信的知道,它是一个顺序访问emps元素的循环,除此之外,你还简化了循环控制,因为没有简洁实用迭代器的必要。所有的这些都提升了代码的抽象层次,这是个好事。
要注意一点,在GotW #2的讨论中,裸for循环在没有通过追加附加的变量执行额外的计算(一个默认的构造函数紧接着一个赋值操作,而不只是一个构造函数)而导致代码更为复杂的情况下,是没有很自然地允许合并到单个return语句的。这对于基于范围的for循环来说还是一样的,因为它依旧是两条return语句在不同的范围内。
2. 。。。使用标准库算法调用?
在没有其他的改变前提下,简单实用标准的find算法做了基于范围for的所有事情,且又避免了不必要的临时对象。
// Better (focusing on internals)
//
string find_addr( /*...*/ ) {
const auto i = find( begin(emps), end(emps), name ); // TFTFY
return i != end(emps) ? i->addr : "";
}
这和基于范围的for版本一样,都消除了相同的临时对象,并且它进一步加强了抽象的层次。我们一眼就能看出,这是一个顺序访问emps元素的循环,但在上一层我们知道是在尝试find一些东西然后返回第一个匹配(如果存在)元素的迭代器。我们依旧间接使用了迭代器,但只是一个一次性的迭代器对象,而不是像原始for版本中的那样对迭代器进行算术运算。
更进一步来说,我们消除了整个循环嵌套域,并且将函数拉平到了一行进行这样简单的函数调用,这是基于范围的for做不到的。为了演示这里一些更基本的要点,注意在拉平函数是还做了其他什么。现在,因为return语句都在一个作用域范围上(可能只是因为我们消除了循环体),我们可以选择地组合它们。当然也可以依旧写成
if( i != end(emps) ) return i->addr; else return “”;
这样,可以一行或者两行或者四行,但是我们没有必要这么做。为了清晰起见,这里的重点不是减少return语句为目的,它也不该是,并且如我们在GotW #2所说,“单退出”总是有缺陷的。这里的重点是使用算法经常可以简化我们的代码不只是一个显示循环,甚至一个rang-for循环。不仅直接通过删除额外的间接对象和额外的变量以及循环嵌套,而且经常也允许在周边代码进行额外的简化。
上述代码在使用一个string比较employee时依旧可能会引发临时对象,如果我们进一步使用一个自定义的比较函数子的find_if的话,那么我们也将比较产生的临时对象都消除了。假设有一些比如employee::name()是可用的就像在GotW #2中一样,将这个于其他的修改组合起来,我们得到了:
// Better still (complete)
//
string find_addr( const list<employee>& emps, const string& name ) {
const auto i = find_if( begin(emps), end(emps),
[&](const auto& e) { return e.name() == name; } );
return i != end(emps) ? i->addr : "";
}
Summary
当你有一个或者可以编写一个合适的算法来完成我们想要的,倾向于使用算法而不是显示的循环。它可以提升我们代码的抽象层次和清晰度。Scott Meyers在Effective STL中的建议依旧是有效的。尤其是现在有着以前没有的lambda。
Guideline:相对于显示的循环,倾向于选择使用算法。算法调用经常可以使代码更清晰且减少复杂度。如果没有合适的算法,那就编写一个。因为我们可能会再次使用它。
优先使用已经存在的库代码而不是自己从无到有地手动编写。越是广泛地使用库,对于许多常见的需求,它就更可能是精心设计的,预调试和预优化的。还有什么比标准库更广泛使用的呢。在你的c++程序中,你的标准库的实现是你可能会使用最广泛使用的库代码。这有助于不管是库的设计还是实现:它所有的代码的目的是被使用和重用,并且很多思想都已经设计到了这些特性中,包括像find和sort这样的标准算法。库的实现者在库的效率、可用性和所有的注意事项方面都下了很大功夫,因此你没有必要---包括执行优化,应该从不依赖应用程序级别的代码,比如使用不可移植的OS或者特定CPU的优化。
因此,总是倾向于重用代码,特别是算法和标准库。要跳出“我编写那些代码只是因为我能”的陷阱。
Guideline:重用代码,特别是标准库代码,而不是自己手动编写自己的版本,因为它更快,更简单,更安全。
[译]GotW #3: Using the Standard Library (or, Temporaries Revisited)的更多相关文章
- [译]The Python Tutorial#11. Brief Tour of the Standard Library — Part II
[译]The Python Tutorial#Brief Tour of the Standard Library - Part II 第二部分介绍更多满足专业编程需求的高级模块,这些模块在小型脚本中 ...
- [译]The Python Tutorial#10. Brief Tour of the Standard Library
[译]The Python Tutorial#Brief Tour of the Standard Library 10.1 Operating System Interface os模块为与操作系统 ...
- Python语言中对于json数据的编解码——Usage of json a Python standard library
一.概述 1.1 关于JSON数据格式 JSON (JavaScript Object Notation), specified by RFC 7159 (which obsoletes RFC 46 ...
- C++ Standard Library
C++ Standard Library *注:内容主要是对參考1的学习记录.知识点与图片大都来源于该书, 部分知识点与图片来源于參考2. 详细參考信息,见最下方參考. * C++98中新支持的语言特 ...
- C++11新特性——The C++ standard library, 2nd Edition 笔记(一)
前言 这是我阅读<The C++ standard library, 2nd Edition>所做读书笔记的第一篇.这个系列基本上会以一章一篇的节奏来写,少数以C++03为主的章节会和其它 ...
- Python Standard Library
Python Standard Library "We'd like to pretend that 'Fredrik' is a role, but even hundreds of vo ...
- Macro definition of snprintf conflicts with Standard Library function declaration
Macro definition of snprintf conflicts with Standard Library function declaration 即将此处的宏定义注释掉,因为在VS2 ...
- 【概念的辨异】—— ISO C 与 POSIX C(C standard library 与 C POSIX library)
ISO C 表示 C Standard Library,也就是 C 标准库. 二者的主要区别在于: POSIX 是 C 标准库的超集(也即是从内容上,C 标准库是 POSIX 库的一部分,POSIX ...
- Swift Standard Library Reference.pdf
Swift Standard Library Reference.pdf 下载地址 http://download.csdn.net/detail/swifttrain/7446331 自己的Mark ...
随机推荐
- ios7之后 根据UILabel的文字计算frame的方法
ios7 新出来的根据label的文字和字体大小来确定label的宽高. 官方的方法是: - (CGRect)boundingRectWithSize:(CGSize)size options:(NS ...
- 清橙 A1120 拦截导弹 -- 动态规划(最长上升子序列)
题目地址:http://oj.tsinsen.com/A1120 问题描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但 ...
- BootstrapDialog点击空白处禁止关闭
在乐学一百的项目当中引用到了BootstrapDialog,其中后台发送短信时,为了防止管理员编辑了半天的短息,突然间因为点击某个空白区域导致丢失,所以在此禁用掉点击空白关闭弹出框. 主要属性为: c ...
- IOPS和Throughput
IOPS和Throughput吞吐量两个参数是衡量存储性能的主要指标.IOPS表示存储每秒传输IO的数量,Throughput吞吐量则表示每秒数据的传输总量.两者在不同的情况下都能表示存储的性能状况, ...
- 面试题(C#基础)
1>构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading. 2>string[] ss=Enum.GetNames(typeof(C ...
- PHP字符
匹配查找 strstr strpos 通常用在表单验证里面可以用到 substr 正值表达式匹配 preg_mathc(), preg)mathc_all() , preg_grep() 编码格式的转 ...
- 【4】创建一个自己的Bootstrap模板
什么也不说了,直接贴上代码吧,哈哈 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta ch ...
- windows 系统下,小数据量Oracle用户物理备份
环境:windows Server 2003 oracle 10g,系统间备份 目标系统创建共享文件,原系统挂载共享目录 写批处理脚本,用任务计划定时调用 Rem * 由于系统实时性要求不是很高,数据 ...
- 【BZOJ】1046 : [HAOI2007]上升序列
1046: [HAOI2007]上升序列 题意:给定S={a1,a2,a3,…,an}问是否存在P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且 ...
- 初识Tower Defense Toolkit
Tower Defense Toolkit 做塔防游戏的插件 主要层次如下图: 1GameControl _ _Game Control(Script) _ _ _Spawn Manager _ _ ...