北京时间2016年1月9日10:31:06。正式開始翻译。水平有限,各位看官若有觉得不妥之处,请批评指正。
之前已经有人翻译了前几个条目,有些借鉴出处:http://www.cnblogs.com/magicsoar/p/3966177.html?utm_source=tuicool&utm_medium=referral
如今就開始《Effective Modern C++》翻译之旅,第一个姿势--简单介绍

Introduction

假设您是一位专家级别的C++project师,和我最初接触C++11的时候想法一样:“是的,我明白了,C++11仅仅只是是比C++多了一点东西而已”。

可是随着您对这个修订后语言的理解加深,你便会被它的变化之大感到震惊。自己主动类型判断、基于范围的for循环、lambda表达式、右值引用等改变了C++的面貌,更不要说新添加的并发特性。

还有那些符合语言特性习惯的变化。0和typedef关键字被淘汰,取而代之的是nullptr表示空指针和别名声明(alias declaration)。枚举有了作用域,智能指针成为了更加完美的内置类型。移动对象往往比拷贝对象更加靠谱。所以,C++11有非常多值得学习的东西。

C++14的通过并没有让这些变得简单。

所以。须要学习的地方非常多。更重要的是,怎样高效的使用这些新特性。

假设您须要C++11的主要的语法和语义,资源总量比較丰富,但假设你正在寻找怎样指导您编写正确的,有效的,可维护代码的资料时。这种搜索非常具挑战性。这就是这本书的原因。

这里不是专门描写叙述的C ++ 11和C ++14的特性,而是告诉你怎样有效的应用C++11。

这本书里的信息分为一条一条的,我们称之为条款

想要理解变量的类型判断?或者想要明白什么时候应该(或者什么时候不应该)使用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 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>                // these are C++
void processVals(const Ts&... params) // source code
{ // ellipses 28
… // this means "some
// code goes here"
}

processVals声明显示了我在声明模板參数的时候使用了typename,这仅仅是个人的偏爱。class在这里相同适用,仅仅在我展示一些来自C++标准中的代码引用的时候,我会使用class声明模板的參数,由于标准里就是这样做的。

当一个对象以还有一个相同类型的对象初始化的时候,这个新的对象被觉得原对象的一个拷贝,即使这个拷贝是经由移动构造创建的,令人遗憾的是。C++中没有不论什么一个技术能够区分一个对象是经由拷贝构造创建的。还是经由移动构造创建的。

void someFunc(Widget w);        // someFunc's parameter w
// is passed by value Widget wid; // wid is some Widget someFunc(wid); // in this call to someFunc,
// w is a copy of wid that's
// created via copy construction someFunc(std::move(wid)); // in this call to SomeFunc,
// w is a copy of wid that's
// created via move construction

右值的拷贝一般是通过移动构造的。左值的拷贝一般是通过拷贝构造的。这里暗示了我们。假设你仅仅知道一个对象是还有一个对象的一个拷贝,你无法知道构造这个拷贝的花费。比方在上面的代码中,当你不知道是一个左值还是一个右值被传递给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;                       // object declaration
class Widget; // class declaration
int func(const Widget& w); // function declaration
enum class Color; // scoped enum declaration
// (see Item 10)

定义提供了它的储存空间和它的实现细节。

class Widget {                      // class definition

}; int func(const Widget& w)
{ return w.size(); } // function definition enum class Color
{ Yellow, Red, Blue }; // scoped enum definition

定义相同包含声明,所以除非某些东西当它作为定义非常重要时,普通情况下,我倾向于使用声明。

新的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

==============================================================

译者凝视:
Pimpl Idiom 它能够用来减少文件间的编译依赖关系

《Effective Modern C++》翻译--简单介绍的更多相关文章

  1. Effective Modern C++翻译(1):序言

    /*********************************************************** 关于书: 书是我从网上找到的effective Modern C++的样章,内 ...

  2. Effective Modern C++翻译(2)-条款1:明白模板类型推导

    第一章 类型推导 C++98有一套单一的类型推导的规则:用来推导函数模板,C++11轻微的修改了这些规则并且增加了两个,一个用于auto,一个用于decltype,接着C++14扩展了auto和dec ...

  3. Effective Modern C++翻译(7)-条款6:当auto推导出意外的类型时,使用显式的类型初始化语义

    条款6:当auto推导出意外的类型时,使用显式的类型初始化语义 条款5解释了使用auto来声明变量比使用精确的类型声明多了了很多的技术优势,但有的时候,当你想要zag的时候,auto可能会推导出了zi ...

  4. Effective Modern C++翻译(4)-条款3:了解decltype

    条款3 了解decltype decltype是一个有趣的东西,给它一个变量名或是一个表达式,decltype会告诉你这个变量名或是这个表达式的类型,通常,告诉你的结果和你预测的是一样的,但是偶尔的结 ...

  5. Effective Modern C++翻译(5)-条款4:了解如何观察推导出的类型

    条款4:了解如何观察推导出的类型 那些想要知道编译器推导出的类型的人通常分为两种,第一种是实用主义者,他们的动力通常来自于软件产生的问题(例如他们还在调试解决中),他们利用编译器进行寻找,并相信这个能 ...

  6. Effective Modern C++翻译(6)-条款5:auto比显示的类型声明要更好

        在概念上说,auto关键字和它看起来一样简单,但是事实上,它要更微妙一些的.使用auto会让你在声明变量时省略掉类型,同时也会防止了手动类型声明带来的正确性和性能上的困扰:虽然按照语言预先定义 ...

  7. Effective Modern C++翻译(3)-条款2:明白auto类型推导

    条款2 明白auto类型推导 如果你已经读完了条款1中有关模板类型推导的内容,那么你几乎已经知道了所有关于auto类型推导的事情,因为除了一个古怪的例外,auto的类型推导规则和模板的类型推导规则是一 ...

  8. 决定干点事儿--翻译一下《effective modern c++》

    写了非常多关于C++11的博客.总是认为不踏实,非常多东西都是东拼西凑.市场上也非常少有C++11的优秀书籍,但幸运的是Meyers老爷子并没有闲赋.为我们带来了<effective moder ...

  9. <<Modern CMake>> 翻译 1. CMake 介绍

    <<Modern CMake>> 翻译 1. CMake 介绍 人们喜欢讨厌构建系统. 仅仅观看 CppCon17 上的演讲,就可以看到开发人员因为构建系统而闹笑话的例子. 这 ...

随机推荐

  1. threejs 组成的3d管道,寻最短路径问题

    threejs 里面的3d管道的每个节点ID是唯一的,且对应x,y,z坐标.那么当需要从A点到B点的时候,可能出现有多条路径可走,此时便需要求出最短行走路径,因此用到一个寻路径算法.我们将问题简化如下 ...

  2. JavaScript系列----函数(Function)篇(4)

    1.什么是函数? 在W3C中函数的定义是这么说的:函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块.   诚然,从这种抽象的定义中我们得不到什么有价值的东西.下面,举例来列举出函数的几种定义 ...

  3. Python学习--语句

    一.print 和 import print 打印多个表达式,用逗号隔开 >>> print 'ab','cd' ab cd import import somemodule fro ...

  4. openstack学习心得:keystone 架构、概念、访问流程

    1.keystone 介绍及其组成 OpenStack Identity 服务提供了一个单一的功能集合,包括管理认证,授权和服务目录. Identity 服务通常作为和用户第一个交互的服务.一旦认证成 ...

  5. oracle存储过程统计用户各表记录数

    declare v_tName varchar(50); v_sqlanalyze varchar(500); v_num number; v_sql varchar(500); cursor c1  ...

  6. android wear开发之:增加可穿戴设备功能到通知中 - Adding Wearable Features to Notifications

    注:本文内容来自:https://developer.android.com/training/wearables/notifications/index.html 翻译水平有限,如有疏漏,欢迎批评指 ...

  7. C#中抽象类和接口的区别3

    一.普通类和抽象类之间的异同 1.都可以被继承 2.抽象类不能被实例化,只是用来继承的.普通类可以实例化 3.抽象方法只有含方法声明而没有方法体且必须包含在抽象类里面 4.子类继承抽象类必须实现抽象类 ...

  8. CLR类型设计之类型之常量和字段

             前言 孔子说:温故而知新,可以为师矣.所以对于学习过的知识要多复习,并且每一次复习都要尽可能的去扩展,而不是书本上的几句理论知识.很多人都喜欢分享自己的学习内容,记录下生活的点点滴滴 ...

  9. python进阶---Python中的socket编程

    初识socket编程 一.前言 socket基于C\S架构(客户端\服务端)的编程模型,在Python中是以socket模块存在的. Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是 ...

  10. MySQL运维相关工具汇总(待补充)

    1.orztop查看show full processlist http://hidba.org/?p=841 2.orzdba查看系统状态信息 http://code.taobao.org/p/or ...