Effective Modern C++翻译(1):序言
/***********************************************************
关于书:
书是我从网上找到的effective Modern C++的样章,内容只到条款4就没有了,
所以现阶段我只能翻译到条款4,不过以后有机会我会继续翻译的。
如果读者找到了完整的版本,欢迎大家发给我。1021842556@qq.com
effective Modern C++的样章的下载地址http://pan.baidu.com/s/1ntKBlpf 提取密码是upkw
关于我:
一名大四的学生,喜欢读书,读好书,求甚解,爱好技术,大学期间也看过了5本技术类的英文书籍,
但翻译英文书的内容还是第一次,所以有些地方翻译的可能不是很到位,还请大家见谅。
感谢郝同学帮助我进行错别字以及语句是否通顺的检查。
*************************************************************/
介绍
如果你是一个有经验的C++程序员,就像我一样,你最初接触C++11的时候会想“恩恩,我明白了,这还是C++,只是多了些东西而已”但是随着你对这个修订后的语言的了解逐渐增长,你会对它的变化之大感到震惊,auto类型,基于范围的for循环,lambada表达式,右值引用这些东西已经改变了C++的面貌,更不用说新增加的并发的特性。还有那些更顺应语言习惯的改变,将0作为指针空值造成的二义性已经不再存在,定义别名也不再是typedef的专属能力,nullptr和新的别名的声明方式加入了进来;枚举有了强类型的作用域;智能指针也比内置的指针更可取了,移动构造通常优于拷贝构造,要想了解C++11,你还有很多东西去学习。
C++14标准已经确认,但麻烦并没有迎刃而解。
所以,有很多的东西需要学习,更重要的是,去学习如何有效率的使用这些新的特性,如果你需要有关现代C++基本语法和语义特性的信息,你可以找到大量的资料,但是你如果想要找到一些指导方针,关于如何利用这些新的特性来创造那些正确的,有效率的,可维护的,可移植的软件的话,这会是一个更有挑战事情,而这就是这本书的目的,它致力于如何有效率的使用那些C++11和C++14的新特性,而不只是单纯的描述这些特性。
这本书里的信息被分割为一条一条的条款,想要明白类型推导的各种形式?想要知道什么时候应该(什么时候不应该)把一个对象声明为auto?对为什么const成员函数应该是线程安全的感兴趣?如何使用std::unique_ptr实现pimpl?为什么你在使用lambda表达式时应该避免默认的变量捕捉形式?或者是std::atomic和volatile的区别和如何正确的使用它们?这些问题的答案你都可以在书中找到,除此之外,这些答案都是平台独立,与标准一致的,这是一本关于可移植的C++的书。
每一个条款构成了一个个指导方针,而不是规则,这是因为指导方针是有例外的,每一个条款的最主要的部分不在于它提出的建议,而是这些建议背后的原理和思考的过程,一旦你读完了这本书,将来是由你来决定在你的项目的环境中,是否应该忽视或者应用这些条款中的指导。这本书的目的不在于告诉你应该做什么,不应该做什么,而是传递一个更深层次的关于这些东西是如何在C++11和C++14中应用的认识。
术语和约定
为了确保我们互相了解,我们需要在一些术语上达成一致,C++有4个标准,每一个以被ISO标准采用的年份命名,C++98,C++03,C++11和C++14,C++98和C++03只是存在一些微妙的技术细节上的差别,所以在这本书里,我把他们都称为C++98。
当我提到C++98的时候,我指的只是C++语言的这个版本,当我提到C++11的时候,我指的是C++11和C++14,因为C++14是C++11的一个有效的超集,当我写C++14的时候,我明确的指的是C++14,如果我只是简单的提到C++,那么它是属于所有语言版本的,因此,我可能会说C++是十分重视效率的(这里指的是所有的C++版本),C++98缺少对并发性的支持(指的仅仅是C++98),C++11支持了lambda表达式(指的C++11和C++14),C++14提供了更普遍的函数返回类型的推导(指的仅仅是C++14)。
C++11最流行的特性很可能是移动语义,移动语义的基础是从表达式中判断是左值或右值,这是因为右值暗示了对象有资格使用移动运算,而左值通常不能。在概念上(尽管并不总是在实践中)右值相对应于从函数返回的匿名的临时变量,而左值相对应于你可以引用的对象,既可以通过指针,也可以通过引用。
一个有用的来判断一个表达式是不是左值方法是看你能不能取得它的地址,如果你能的话,它通常就是一个左值,如果你不能的话,它通常是一个右值。这个方法的一个好的特性在于它帮助你记住了一个表达式的类型和这个表达式代表的是一个左值还是一个右值是无关的,给一个类型T,你即可以即可以获得T的左值类型,也可以获得T的右值类型,这是十分重要的,尤其是当你处理一个右值的引用参数的时候,因为这个时候参数本身是一个左值。
class Widget {
public:
Widget(Widget&&
rhs
); // rhs是一个左值,尽管它有一个(rhs is an lvalue, though it has)
// 右值的引用类型(an rvalue reference type)
};
这里,在widgt的移动构造函数中取得rhs参数的地址是完全合法的,所以rhs是一个左值,尽管它的类型是一个右值的引用(类似的推理,一切参数都是左值)。
这段代码展示了很多我通常遵循的约定,
类的名字是widget,我使用widget当我想要表示一个任意的用户自定义类型的时候,我会不加声明的使用widget,除了某些时候,我需要展示类的特殊的细节。
我把参数命名为rhs,代表了right-hand side,这是我在使用移动操作(比如移动构造,移动赋值)和拷贝操作(比如拷贝构造,拷贝赋值)时比较偏爱的名字,尽管我在使用二元运算符也通常使用rhs作为右面参数的名字。
Matrix operator+(const Matrix& lhs,const Matrix& rhs);
我希望这不会令你感到惊讶,lhs代表了left-hand side;
我突出加亮了代码或者注释的部分内容,来使你的注意力集中到上面去,在上面的代码中,我加亮了rhs和注释的部分内容,使你注意到rhs是一个左值。
我使用“…”来暗示这里会有其他的代码,这里窄的省略号和宽的省略号(“. . .”)间是有区别的,宽的省略号是在C++11中作为变长模板使用的,这听起来有点令人困惑,其实不是,例如
template<typename... Ts> // 这是C++代码里的
void processVals(const Ts&... params) // 省略号
{
… // 意味指这里还有一些代码
}
processVals声明显示了我在声明模板参数的时候使用了typename,这只是个人的偏爱,class在这里同样适用,仅仅在我展示一些来自C++标准中的代码引用的时候,我会使用class声明模板的参数,因为标准里就是这样做的。
当一个对象以另一个同样类型的对象初始化的时候,这个新的对象被认为原对象的一个拷贝,即使这个拷贝是经由移动构造创建的,令人遗憾的是,C++中没有任何一个技术可以区分一个对象是经由拷贝构造创建的,还是经由移动构造创建的。
void someFunc(Widget w); // someFunc的参数
// 是经由值传递 Widget wid; // wid是Widget类型的对象
someFunc(wid); // 在这个函数调用中,
// w是wid经由拷贝构造创建的
// 一个拷贝
someFunc(std::move(wid)); // 在这个函数调用中
// w是wid经由移动构造创建的
// 一个拷贝
右值的拷贝通常是通过移动构造的,左值的拷贝通常是通过拷贝构造的,这里暗示了我们,如果你仅仅知道一个对象是另一个对象的一个拷贝,你无法知道构造这个拷贝的花费,比如在上面的代码中,当你不知道是一个左值还是一个右值被传递给someFunc的参数w的时,你无法知道创建参数w所需要的花费(你同样需要知道拷贝构造和一个构造widget的花费)。
在一个函数调用中,调用端的表达式是这个函数的实参(argument),这些参数被用来实例化函数的形参(parameters),在第一个例子中,实参是wid,在第二个例子中,实参是std::move(wid),在这两个例子中, 形参都是w,形参和实参的区别是很重要的,因为形参是左值,但是实参和实例化这些实参的却可能是左值或是右值,这个和完美转发(perfect forwarding)的过程相关,完美转发是指将参数传递给函数中调用的第二个函数,原来参数的左值和右值性得以保留(完美转发的更多细节将在条款32中进行讨论)。
精心设计的函数是异常安全的(exception-safe),这意味着他们至少提供了最基本的异常安全保证(即基本承诺basic guarantee),这样的函数向调用者确保了即使有一个异常产生了,程序的不变量依旧是完整的(即没有任何数据结构被破坏),也没有任何资源的泄露,那些提供了强烈的异常安全保证(即强烈保证strong guarantee)的函数,向调用者确保了如果有一个异常产生了,程序的状态和调用前是一样的。就像条款16解释的那样,C++98标准类库里的函数提供了强烈保证约束对于C++11标准类库里的移动语义(C++98 Standard Library functions offering the strong guarantee constrain the applicability of move semantics in the C++11 Standard Library.)。
我使用术语可调用物(callable entity)来描述可以和调用非成员函数一样的调用语法的任何东西,比如,语法“functionName(arguments)“,函数,函数指针,函数对象都是可调用物(callable entity),通过lambda表达式创建的函数对象被称为闭包(closures),很少有必要去区分一个lambda表达式和它们创建的闭包,所以我把它们都称作lambdas。
同样的,我几乎不区分函数模板(即产生函数的模板)和模板函数(即从模板里实例化的函数),类模板和模板类也一样。
C++里的很多东西可以被声明和定义,声明给出了它的名字,却没有给出太多的细节,比如它的储存空间和它是如何实现的。
extern int x; // 对象声明
class Widget; // 类声明
int func(const Widget& w); // 函数声明
enum class Color; // 有作用域的枚举的声明
// (见条款10)
定义提供了它的储存空间和它的实现细节。
int x; // 对象定义 class Widget { // 类定义
…
};
int func(const Widget& w)
{ return w.size(); } // 函数定义
enum class Color
{ Yellow, Red, Blue }; // 有作用域的枚举的定义
定义同样包括声明,所以除非某些东西当它作为定义很重要时,一般情况下,我倾向于使用声明。
新的C++标准保留了原有的在旧的标准下写的代码的有效性,但是标准委员会偶尔也会弃用(deprecates)一些特性,这警告一个特性可能会在未来的标准中被移除,你应该避免使用这些被弃用的特性(被弃用的原因通常是新的特性提供了一样的功能,但是带有更少的限制和缺点),例如std::auto_ptr在C++11中被弃用,因为std::unique_ptr提供了同样的功能,而且做的更好。
有时,标准会说一个操作的结果是未定义的(undefined behavior),这意味着运行时的行为是无法预测的,毫无疑问,你想要避开这样的不确定性,未定义的行为有使用中括号([])时下标超过了std::vector的界限,解引用一个未实例化的迭代器,或者涉及到数据竞争(例如有两个以上的线程,至少一个是写者,同时访问一个内存单元)。
在源代码的注释中,我有时把construct缩写为ctor,把destructor缩写为dtor。
报告bugs和改进的建议
我尽我所能的让这本书充满了清晰,具体,有用的信息,但是肯定还有一些方式使它变的更好,如何你发现了任何形式的错误(技术的,解释说明的,文法的,排版的等等),或者你有关于改进这本书的建议,请给我发邮件,我的邮箱是emc++@aristeia.com,新的印刷给我机会来修订Effective Modern C++,但我无法解决我不知道的问题。
如何想查看 已知的问题的列表,可以查阅本书的勘误页,网址是:
http://www.aristeia.com/BookErrata/emc++-errata.html
/***********************************************************
才发现博客园6小时内只能在网站首页发布1篇随笔,
所以下一篇文章在这里Effective Modern C++翻译(2)-条款1
***********************************************************/
Effective Modern C++翻译(1):序言的更多相关文章
- Effective Modern C++翻译(7)-条款6:当auto推导出意外的类型时,使用显式的类型初始化语义
条款6:当auto推导出意外的类型时,使用显式的类型初始化语义 条款5解释了使用auto来声明变量比使用精确的类型声明多了了很多的技术优势,但有的时候,当你想要zag的时候,auto可能会推导出了zi ...
- Effective Modern C++翻译(4)-条款3:了解decltype
条款3 了解decltype decltype是一个有趣的东西,给它一个变量名或是一个表达式,decltype会告诉你这个变量名或是这个表达式的类型,通常,告诉你的结果和你预测的是一样的,但是偶尔的结 ...
- Effective Modern C++翻译(3)-条款2:明白auto类型推导
条款2 明白auto类型推导 如果你已经读完了条款1中有关模板类型推导的内容,那么你几乎已经知道了所有关于auto类型推导的事情,因为除了一个古怪的例外,auto的类型推导规则和模板的类型推导规则是一 ...
- Effective Modern C++翻译(2)-条款1:明白模板类型推导
第一章 类型推导 C++98有一套单一的类型推导的规则:用来推导函数模板,C++11轻微的修改了这些规则并且增加了两个,一个用于auto,一个用于decltype,接着C++14扩展了auto和dec ...
- Effective Modern C++翻译(5)-条款4:了解如何观察推导出的类型
条款4:了解如何观察推导出的类型 那些想要知道编译器推导出的类型的人通常分为两种,第一种是实用主义者,他们的动力通常来自于软件产生的问题(例如他们还在调试解决中),他们利用编译器进行寻找,并相信这个能 ...
- Effective Modern C++翻译(6)-条款5:auto比显示的类型声明要更好
在概念上说,auto关键字和它看起来一样简单,但是事实上,它要更微妙一些的.使用auto会让你在声明变量时省略掉类型,同时也会防止了手动类型声明带来的正确性和性能上的困扰:虽然按照语言预先定义 ...
- 《Effective Modern C++》翻译--简单介绍
北京时间2016年1月9日10:31:06.正式開始翻译.水平有限,各位看官若有觉得不妥之处,请批评指正. 之前已经有人翻译了前几个条目,有些借鉴出处:http://www.cnblogs.com/m ...
- 决定干点事儿--翻译一下《effective modern c++》
写了非常多关于C++11的博客.总是认为不踏实,非常多东西都是东拼西凑.市场上也非常少有C++11的优秀书籍,但幸运的是Meyers老爷子并没有闲赋.为我们带来了<effective moder ...
- <<Modern CMake>> 翻译 1. CMake 介绍
<<Modern CMake>> 翻译 1. CMake 介绍 人们喜欢讨厌构建系统. 仅仅观看 CppCon17 上的演讲,就可以看到开发人员因为构建系统而闹笑话的例子. 这 ...
随机推荐
- LintCode "Binary Representation"
Not hard to think of a solution. But the key is all details. class Solution { public: /** *@param n: ...
- java连接mongodb的一个奇葩问题及奇葩解决方式
昨天在eclipse中编写代码,本来连接mongodb进行各项操作都是正常的,但是有一会儿突然之间就没法连接了,还一直抱错,错误如下: 信息: Cluster created with setting ...
- 【转 】实战手记:让百万级数据瞬间导入SQL Server
想必每个DBA都喜欢挑战数据导入时间,用时越短工作效率越高,也充分的能够证明自己的实力.实际工作中有时候需要把大量数据导入数据库,然后用于各种程序计算,本文将向大家推荐一个挑战4秒极限让百万级数据瞬间 ...
- visual studio 2013 中常用的一些快捷键
在编辑代码或者复制网上的代码段到VS2013中时,代码会显示的非常乱,这里便可以通过 vs2013中的快捷键进行自动对齐操作[ctrl+k+f],类似的快捷操作还有很多,在这里给大家总结一下,以提高编 ...
- 黄聪:PHP字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、切割成数组等)
一.字符串替换 str_replace("iwind", "kiki", "i love iwind, iwind said"); 将输出 ...
- C#学习笔记五: C#3.0Lambda表达式及Linq解析
最早使用到Lambda表达式是因为一个需求:如果一个数组是:int[] s = new int[]{1,3,5,9,14,16,22};例如只想要这个数组中小于15的元素然后重新组装成一个数组或者直接 ...
- Log4Net在Windows服务中不能记录日志 z
解决方案: 在Windows安装服务的“serviceProcessInstaller1”中修改Account属性为LocalSystem.见下图 后来查了一下这个Account属性 说白了还是权限的 ...
- Good Sentences
Wine in, truth out One is never too old to learn What is done can not be undone Time tries all thing ...
- 解决docker不能下载镜像
试了很多办法.用ss,vpn,都不行. 修改 /etc/default/docker的方式貌似在 1.12不好使了.最后找到和这个办法 http://blog.csdn.net/gsying1474/ ...
- 三种主流的WebService实现方案(REST/SOAP/XML-RPC)简述及比较
目前知道的三种主流的Web服务实现方案为:REST:表象化状态转变 (软件架构风格)SOAP:简单对象访问协议 XML-RPC:远程过程调用协议 简单介绍: REST:表征状态转移(Represent ...