高效的代码重用是良好的软件工程中重要的一部分。为了演示如何更好地通过使用标准库算法而不是手工编写,我们再次考虑先前的问题。演示通过简单利用标准库中已有的算法来避免的一些问题。

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:重用代码,特别是标准库代码,而不是自己手动编写自己的版本,因为它更快,更简单,更安全。

原文地址:http://herbsutter.com/2013/05/16/gotw-3-solution-using-the-standard-library-or-temporaries-revisited/

[译]GotW #3: Using the Standard Library (or, Temporaries Revisited)的更多相关文章

  1. [译]The Python Tutorial#11. Brief Tour of the Standard Library — Part II

    [译]The Python Tutorial#Brief Tour of the Standard Library - Part II 第二部分介绍更多满足专业编程需求的高级模块,这些模块在小型脚本中 ...

  2. [译]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模块为与操作系统 ...

  3. Python语言中对于json数据的编解码——Usage of json a Python standard library

    一.概述 1.1 关于JSON数据格式 JSON (JavaScript Object Notation), specified by RFC 7159 (which obsoletes RFC 46 ...

  4. C++ Standard Library

    C++ Standard Library *注:内容主要是对參考1的学习记录.知识点与图片大都来源于该书, 部分知识点与图片来源于參考2. 详细參考信息,见最下方參考. * C++98中新支持的语言特 ...

  5. C++11新特性——The C++ standard library, 2nd Edition 笔记(一)

    前言 这是我阅读<The C++ standard library, 2nd Edition>所做读书笔记的第一篇.这个系列基本上会以一章一篇的节奏来写,少数以C++03为主的章节会和其它 ...

  6. Python Standard Library

    Python Standard Library "We'd like to pretend that 'Fredrik' is a role, but even hundreds of vo ...

  7. Macro definition of snprintf conflicts with Standard Library function declaration

    Macro definition of snprintf conflicts with Standard Library function declaration 即将此处的宏定义注释掉,因为在VS2 ...

  8. 【概念的辨异】—— ISO C 与 POSIX C(C standard library 与 C POSIX library)

    ISO C 表示 C Standard Library,也就是 C 标准库. 二者的主要区别在于: POSIX 是 C 标准库的超集(也即是从内容上,C 标准库是 POSIX 库的一部分,POSIX ...

  9. Swift Standard Library Reference.pdf

    Swift Standard Library Reference.pdf 下载地址 http://download.csdn.net/detail/swifttrain/7446331 自己的Mark ...

随机推荐

  1. 使用PHP连接、操纵Memcached的原理和教程

    http://www.crazyant.net/1014.html Memcahced开源分布式内存对象缓存系统通过减少数据库的负担,从而能够加速你的web应用.在本文中我将解释怎样实现一个基于Mem ...

  2. 合理配置MySQL缓存 提高缓存命中率

    众所周知,系统读取数据时,从内存中读取要比从硬盘上速度要快好几百倍.故现在绝大部分应用系统,都会最大程度的使用缓存(内存中的一个存储区域),来提高系统的运行效率.MySQL数据库也不例外.在这里,笔者 ...

  3. (转)安装程序发布利器——InstallShield 2011 Limited Edition

    最近经常写WCF服务和Windows服务,之前知道可以通过vs2010自带的“安装项目”可以发布程序,但是自vs2010起,同时提供了InstallShield LE. 下面我们通过图示,来了解Ins ...

  4. redis 实践—— sorted set, hash set

    在这里就不谈redis的安装与启动啦,网上太多人写这个了. 从最近的一个项目[钻石夺宝]说起,如果大家有玩过一元夺宝或者全名夺宝的话,大概会知道如果参与人数多的话,每隔几秒.快的话每隔一秒都会新生成一 ...

  5. Thrift原理与使用实例

    一 Thrift框架介绍 1 前言 Thrift是一个跨语言的服务部署框架,最初由Faceboo开发并进入Apache开源项目. Thrift特征如下: 1)Thrift有自己的跨机器通信框架,并提供 ...

  6. Windows Phone 动态改变ListBox样式

    使用ListBox时通常会借助ItemTemplate帮助我们实现更复杂多样的样式显示,体现了Xaml的灵活.如何动态改变变ListBox的样式,实现类似电脑资源管理器中列表显示和图标显示形式的替换. ...

  7. C语言中的程序终止函数

    在C语言的标准库<stdlib.h>中提供了一些与正常或者不正常的程序终止有关的函数,下面分别对其进行简单介绍. 参考文献: [1] C和指针,P298,342 [2] C程序设计语言现代 ...

  8. 栈(顺序存储)C++模板实现

    #include <iostream> using namespace std; template <typename T> class stack{ private: int ...

  9. Apache虚拟主机设置

    Apache支持两种虚拟主机,一种是基于IP地址的,一种是基于域名的. 基于IP地址的虚拟机现在使用的很少,它需要一台服务器需要拥有多个IP地址.基于域名的虚拟主机要求服务器有一个IP地址就可以了,只 ...

  10. 简单的NHibernate学习笔记

    NHibernate是.NET平台下的ORM框架,与ADO.NET一样实现项目中数据库与项目系统的交互. .首先要用NHibernate框架就要有第三方的dll库来作为支持,附上百度云下载地址:(链接 ...