[译]GotW #1: Variable Initialization 续
Answer 2. 下面每行代码都做了什么?
在Q2中,我们创建了一个vector<int>且传了参数10和20到构造函数中,第一种情况下(10,20),第二种情况是{10, 20}。
它们都将调用构造函数,但是是哪个?vector<int>有好几个带两个参数的构造函数,但只有两个能在参数10和20下正确调用。为了简单,在此忽略了默认可选的allocator参数。这两个构造函数是:
vector( size_t n, const int& value ); // A: n copies of value vector( initializer_list<int> values ); // B: copy of values
有两个简单的C++规则可以告诉我们上面问题中哪个会被调用:
· 在表达式上下文中使用语法{ /*…*/ }将会带来initializer_list。
· 带initializer_list参数的构造函数会优先于其他构造函数,这样可以隐藏其他可能会是可行的构造函数。
使用两个小缀饰,答案就变得简单了:
vector<int> v1( 10, 20 ); // (a) calls A: 10 copies of the value 20
assert( v1.size() == 10 ); vector<int> v2{ 10, 20 }; // (b) calls B: the values 10 and 20
assert( v2.size() == 2 );
Answer 3. 除了上面代码,使用{}初始化对象还有什么其他好处?
首先,它被称为“统一初始化”,因为它对所有类型都是一样的,包括aggregate structs、数组和std::containers,且没有恼人的“棘手的解析”:
struct mystruct { int x, y; }; // C++98
rectangle w( origin(), extents() ); // oops, vexing parse
complex<double> c( 2.71828, 3.14159 );
mystruct m = { 1, 2 };
int a[] = { 1, 2, 3, 4 };
vector<int> v; // urk, need more code
for( int i = 1; i <= 4; ++i ) v.push_back(i); // to initialize this // C++11 (note: "=" is mostly optional)
rectangle w = { origin(), extents() };
complex<double> c = { 2.71828, 3.14159 };
mystruct m = { 1, 2 };
int a[] = { 1, 2, 3, 4 };
vector<int> v = { 1, 2, 3, 4 };
要注意的是这不仅仅是一个美学上的问题。在写通用代码的时候应该能初始化任意类型,下面使用perfect forwarding演示一个例子:
template<typename T, typename ...Args>
void forwarder( Args&&... args ) {
// ...
T local = { std::forward<Args>(args)... };
// ...
} forwarder<int> ( 42 ); // ok
forwarder<rectangle> ( origin(), extents() ); // ok
forwarder<complex<double>>( 2.71828, 3.14159 ); // ok
forwarder<mystruct> ( 1, 2 ); // ok because of {}
forwarder<int[]> ( 1, 2, 3, 4 ); // ok because of {}
forwarder<vector<int>> ( 1, 2, 3, 4 ); // ok because of {}
最后3行如果在forwarder内部使用()来初始化的话是不合法的。
新的{}语法在几乎在任何地方都能工作,包括初始化成员:
widget::widget( /*...*/ ) : mem1{init1}, mem2{init2, init3} { /*...*/ }
在传函数参数或者返回一个值(没有类型名的临时对象)也非常方便:
void draw_rect( rectangle ); draw_rect( rectangle(origin, selection) ); // C++98
draw_rect({ origin, selection }); // C++11 rectangle compute_rect() {
// ...
if(cpp98) return rectangle(origin, selection); // C++98
else return {origin, selection}; // C++11
}
Answer 4. 在什么时候应该使用()或者{ }语法来初始化对象?为什么?
这有一些简单的指南:
Guideline:优先使用{}进行初始化,比如:vector<int> v = { 1, 2, 3, 4 };或auto v = vector<int>{ 1, 2, 3, 4 };(译注:※2)。因为它更一致,更正确,且完全避免了一些老式的陷阱。在单参数情况下,你可能会只看见=符号,比如:int i = 42;或者auto x = anything;省略花括号是OK的。。。
这覆盖了大部分情况,只有一个主要的例外情况:
在很少情况下,比如:vector<int> v(10,20);或者auto v = vector<int>(10,20);。显示地使用()被initializer_list构造函数隐藏的构造函数进行初始化。
然而,这应该是很少见的情况,因为默认和拷贝构造函数已经可以和{}一起工作,一个类的好的设计为了用户定义的构造函数,现在应该通常避免还原到()的情况,所有有了最后一条设计指南:
Guideline: 当设计一个类,避免提供一个与initializer_list构造函数有二义性的构造函数,因此用户不需要使用()来达到调用被隐藏的构造函数。
※:真心不太好翻译,这里red herring应该不是字面意思。
※2:这条语句至少在VS12 CTP版的编译器上是通不过编译的。http://rise4fun.com/Vcpp/r60
[译]GotW #1: Variable Initialization 续的更多相关文章
- [译]GotW #1: Variable Initialization
原文地址:http://herbsutter.com/2013/05/09/gotw-1-solution/ 第一个问题强调的是要明白自己在写什么的重要性.下面有几行简单的代码--它们大多数之间都有区 ...
- [译]GotW #6a: Const-Correctness, Part 1
const 和 mutable在C++存在已经很多年了,对于如今的这两个关键字你了解多少? Problem JG Question 1. 什么是“共享变量”? Guru Question 2. con ...
- [译]GotW #89 Smart Pointers
There's a lot to love about standard smart pointers in general, and unique_ptr in particular. Proble ...
- [译]GotW #6b Const-Correctness, Part 2
const和mutable对于书写安全代码来说是个很有利的工具,坚持使用它们. Problem Guru Question 在下面代码中,在只要合适的情况下,对const进行增加和删除(包括 ...
- [译]GotW #4 Class Mechanics
你对写一个类的细节有多在行?这条款不仅注重公然的错误,更多的是一种专业的风格.了解这些原则将会帮助你设计易于使用和易于管理的类. JG Question 1. 什么使得接口“容易正确使用,错误使用却很 ...
- [译]GotW #3: Using the Standard Library (or, Temporaries Revisited)
高效的代码重用是良好的软件工程中重要的一部分.为了演示如何更好地通过使用标准库算法而不是手工编写,我们再次考虑先前的问题.演示通过简单利用标准库中已有的算法来避免的一些问题. Problem JG Q ...
- [译]GotW #2: Temporary Objects
不必要的和(或)临时的变量经常是罪魁祸首,它让你在程序性能方面的努力功亏一篑.如何才能识别出它们然后避免它们呢? Problem JG Question: 1. 什么是临时变量? Guru Q ...
- [译]GotW #5:Overriding Virtual Functions
虚函数是一个很基本的特性,但是它们偶尔会隐藏在很微妙的地方,然后等着你.如果你能回答下面的问题,那么你已经完全了解了它,你不太能浪费太多时间去调试类似下面的问题. Problem JG Ques ...
- 【ZZ】C++11之统一初始化语法 | 桃子的博客志
C++11之统一初始化语法 | 桃子的博客志 https://taozj.net/201710/list-initialize.html 在当前新标准C++11的语法看来,变量合法的初始化器有如下形式 ...
随机推荐
- js购物时的放大镜效果
首先需要两张一样的图片,一张大图,一张小图,大图显示,当鼠标移入时,小图上出现一个滑块,可以滑动,大图也跟着显示,大图的显示区域和小图一样,当滑块滑到不同的位置,大图显示不同的区域,当鼠标移出时,滑块 ...
- Java联网技术之一TCP
最近突然对java网络编程编程这一块非常感兴趣,于是找了很多资料,一点点的尝试,下面是自己的一点小见解,不喜勿喷,欢迎指正. 首先说说客户端和服务器端吧, 如果是网页的话,客户端通过网页的链接对服务器 ...
- 通过Web.config中的configSections配置自己系统的全局常量
通过Web.config中的configSections配置自己系统的全局常量 随着系统的庞大,你的全局信息保存在appsitting里可能会比较乱,不如为模块写个自定义的全局常量吧 首先在Web.C ...
- WORDPRESS 后台500错误解决方法集合
引自: http://www.guuglc.com/565.html 这篇文章本质上我是不可能会写到,就因为7号那天晚上,我准备搬家的时候,发现前台完好,进入后台却500错误. 这时我就得急的,毕竟明 ...
- 执行mysql脚本
方法1: mysql -uroot -p123456 -Ddatabasename < sql文件路径 方法2: source 路径全名 \. 路径全名
- javascript dom编程艺术笔记第三章:DOM操作的5个基本方法
JavaScript的 DOM操作,主要是对DOM这三个字母中D.O.M的操作.D代表的是document(文档),即我们可以使用javascript对文档进行操作,O代表的是object(对象),对 ...
- 转:HashMap的工作原理,及笔记
HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如此 ...
- 你喜欢使用eclipse+tomcat编程吗?!
在eclipse中配置tomcat简直是一场灾难! 开源软件确实给开发者极大的自由,但,同时也带来额外的麻烦. eclipse+tomcat只是其中之一.我有幸碰到了N次,在N+1次时,不得不提笔撰文 ...
- go build 时报错 cc1.exe: sorry, unimplemented: 64-bit mode not compiled in
最近在玩Go win下尝试编译Go的时候遇到了下面提示(可能是gorocksdb用到了gcc) gcc也需要64位的 最后找到了个帖子: https://github.com/mattn/go-sql ...
- python 自动化之路 day 06
ATM作业讲解: 数据访问层 业务逻辑层 time & datetime模块 import time # print(time.clock()) #返回处理器时间,3.3开始已废弃 , 改成了 ...