mirror of
https://github.com/CnTransGroup/EffectiveModernCppChinese.git
synced 2025-01-01 16:00:37 +08:00
commit
ed7a9aaef3
@ -82,6 +82,7 @@ dereUPLess = [](const std::unique_ptr<Widget> &p1,
|
||||
const std::unique_ptr<Widget> &p2){return *p1<*p2;};
|
||||
````
|
||||
语法冗长不说,还需要重复写很多形参类型,使用`std::function`还不如使用auto。用auto声明的变量保存一个闭包这个变量将会得到和闭包一样的类型。
|
||||
|
||||
实例化`std::function`并声明一个对象这个对象将会有固定的大小。当使用这个对象保存一个闭包时它可能大小不足不能存储,这个时候`std::function`的构造函数将会在堆上面分配内存来存储,这就造成了使用`std::function`比auto会消耗更多的内存。并且通过具体实现我们得知通过std::function调用一个闭包几乎无疑比auto声明的对象调用要慢。
|
||||
换句话说,std::function方法比auto方法要更耗空间且更慢,并且比起写一大堆类型使用auto要方便得多。在这场存储闭包的比赛中,auto无疑取得了胜利(也可以使用std::bind来生成一个闭包,但在Item34我会尽我最大努力说服你使用lambda表达式代替std::bind)
|
||||
|
||||
@ -109,7 +110,7 @@ for(const std::pair<std::string,int>& p : m)
|
||||
````
|
||||
看起来好像很合情合理的表达,但是这里有一个问题,你看到了吗?
|
||||
|
||||
要想看到错误你就得知道std::unordered_map的key是一个常量,所以std::pair的类型不是std::pair<std::string,int>而是std::pair<const std::string,int>。编译器会努力的找到一种方法把前者转换为后者。它会成功的,因为它会创建一个临时对象,这个临时对象的类型是p想绑定到的对象的类型,即m中元素的类型,然后把p的引用绑定到这个临时对象上。在每个循环迭代结束时,临时对象将会销毁,如果你写了这样的一个循环,你可能会对它的一些行为感到非常惊讶,因为你确信你只是让成为p指向m中各个元素的引用而已。
|
||||
要想看到错误你就得知道`std::unordered_map`的key是一个常量,所以`std::pair`的类型不是`std::pair<std::string,int>`而是`std::pair<const std::string,int>`。编译器会努力的找到一种方法把前者转换为后者。它会成功的,因为它会创建一个临时对象,这个临时对象的类型是p想绑定到的对象的类型,即m中元素的类型,然后把p的引用绑定到这个临时对象上。在每个循环迭代结束时,临时对象将会销毁,如果你写了这样的一个循环,你可能会对它的一些行为感到非常惊讶,因为你确信你只是让成为p指向m中各个元素的引用而已。
|
||||
|
||||
使用auto可以避免这些很难被意识到的类型不匹配的错误:
|
||||
````cpp
|
||||
@ -123,8 +124,11 @@ for(const auto & p : m)
|
||||
后面这两个例子说明了显式的指定类型可能会导致你不像看到的类型转换。如果你使用auto声明目标变量你就不必担心这个问题。
|
||||
|
||||
基于这些原因我建议你优先考虑auto而非显式类型声明。然而auto也不是完美的。每个auto变量都从初始化表达式中推导类型,有一些表达式的类型和我们期望的大相径庭。关于在哪些情况下会发生这些问题,以及你可以怎么解决这些问题我们在Item2和6讨论,所以这里我不再赘述。我想把注意力放到你可能关心的另一点:使用auto代替传统类型声明对源码可读性的影响。
|
||||
|
||||
首先,深呼吸,放松,auto是**可选项**,不是**命令**,在某些情况下如果你的专业判断告诉你使用显式类型声明比auto要更清晰更易维护,那你就不必再坚持使用auto。牢记C++没有在其他众所周知的语言所拥有的类型接口上开辟新土地。
|
||||
|
||||
其他静态类型的过程式语言(如C#,D,Sacla,Visual Basic等)或多或少的都有那些非静态类型的函数式语言(如ML,Haskell,OCaml.F#等)的特性。在某种程度上,几乎没有显式类型使得动态类型语言Perl,Python,Ruby等取得了成功,软件开发社区对于类型接口有丰富的经验,他们展示了在维护大型工业强度的代码上使用这种技术没有任何争议。
|
||||
|
||||
一些开发者也担心使用auto就不能瞥一眼源代码便知道对象的类型,然而,IDE扛起了部分担子,在很多情况下,少量显示一个对象的类型对于知道对象的确切类型是有帮助的,这通常已经足够了。举个例子,要想知道一个对象是容器还是计数器还是智能指针,不需要知道它的确切类型,一个适当的变量名称就能告诉我们大量的抽象类型信息。
|
||||
|
||||
真正的问题是显式指定类型可以避免一些微妙的错误,以及更具效率和正确性,而且,如果初始化表达式改变变量的类型也会改变,这意味着使用auto可以帮助我们完成一些重构工作。举个例子,如果一个函数返回类型被声明为int,但是后来你认为将它声明为long会更好,调用它作为初始化表达式的变量会自动改变类型,但是如果你不使用auto你就不得不在源代码中挨个找到调用地点然后修改它们。
|
||||
|
Loading…
Reference in New Issue
Block a user