猿问

为什么列表初始化(使用大括号)比其他方法更好?

为什么列表初始化(使用大括号)比其他方法更好?

MyClass a1 {a};     // clearer and less error-prone than the other threeMyClass a2 = {a};MyClass a3 = a;MyClass a4(a);

为什么?

我找不到答案,所以让我回答我自己的问题。


慕勒3428872
浏览 760回答 3
3回答

慕工程0101907

基本上是从Bjarne Stroustrup那里复制和粘贴的C+编程语言第4版:列表初始化不允许缩小范围(§iso.8.5.4)。即:一个整数不能转换为另一个不能保存其值的整数。例如,char to int是允许的,而不是int to char。浮点值不能转换为另一种不能保存其值的浮点类型.例如,允许浮动到双倍,但不允许双倍浮动。浮点值不能转换为整数类型.整数值不能转换为浮点类型.例子:void&nbsp;fun(double&nbsp;val,&nbsp;int&nbsp;val2)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;x2&nbsp;=&nbsp;val;&nbsp;//&nbsp;if&nbsp;val==7.9,&nbsp;x2&nbsp;becomes&nbsp;7&nbsp;(bad) &nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;c2&nbsp;=&nbsp;val2;&nbsp;//&nbsp;if&nbsp;val2==1025,&nbsp;c2&nbsp;becomes&nbsp;1&nbsp;(bad) &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;x3&nbsp;{val};&nbsp;//&nbsp;error:&nbsp;possible&nbsp;truncation&nbsp;(good) &nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;c3&nbsp;{val2};&nbsp;//&nbsp;error:&nbsp;possible&nbsp;narrowing&nbsp;(good) &nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;c4&nbsp;{24};&nbsp;//&nbsp;OK:&nbsp;24&nbsp;can&nbsp;be&nbsp;represented&nbsp;exactly&nbsp;as&nbsp;a&nbsp;char&nbsp;(good) &nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;c5&nbsp;{264};&nbsp;//&nbsp;error&nbsp;(assuming&nbsp;8-bit&nbsp;chars):&nbsp;264&nbsp;cannot&nbsp;be&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;represented&nbsp;as&nbsp;a&nbsp;char&nbsp;(good) &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;x4&nbsp;{2.0};&nbsp;//&nbsp;error:&nbsp;no&nbsp;double&nbsp;to&nbsp;int&nbsp;value&nbsp;conversion&nbsp;(good)}这个只使用时,=优于{}的情况auto关键字,以获取由初始化器确定的类型。例子:auto&nbsp;z1&nbsp;{99};&nbsp;//&nbsp;z1&nbsp;is&nbsp;an&nbsp;initializer_list<int>auto&nbsp;z2&nbsp;=&nbsp;99;&nbsp;//&nbsp;z2&nbsp;is&nbsp;an&nbsp;int结语喜欢{}初始化而不是其他选项,除非您有很强的理由不这样做。

蝴蝶不菲

使用大括号初始化有很多原因,但是您应该知道这个initializer_list<>构造函数优于其他构造函数。,异常是默认构造函数。这将导致构造函数和模板出现问题,其中类型T构造函数可以是初始化程序列表,也可以是普通的旧ctor。struct&nbsp;Foo&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;Foo()&nbsp;{} &nbsp;&nbsp;&nbsp;&nbsp;Foo(std::initializer_list<Foo>)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"initializer&nbsp;list"&nbsp;<<&nbsp;std::endl; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;Foo(const&nbsp;Foo&)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;<<&nbsp;"copy&nbsp;ctor"&nbsp;<<&nbsp;std::endl; &nbsp;&nbsp;&nbsp;&nbsp;}};int&nbsp;main()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;Foo&nbsp;a; &nbsp;&nbsp;&nbsp;&nbsp;Foo&nbsp;b(a);&nbsp;//&nbsp;copy&nbsp;ctor &nbsp;&nbsp;&nbsp;&nbsp;Foo&nbsp;c{a};&nbsp;//&nbsp;copy&nbsp;ctor&nbsp;(init.&nbsp;list&nbsp;element)&nbsp;+&nbsp;initializer&nbsp;list!!!}假设您没有遇到这样的类,那么就没有什么理由不使用减缩器列表了。

守着星空守着你

关于使用列表初始化的优点,已经有了很好的答案,但是我个人的经验法则不是尽可能使用大括号,而是让它依赖于概念意义:如果我正在创建的对象在概念上持有我在构造函数中传递的值(例如容器、POD结构、Atomics、智能指针等),那么我将使用大括号。如果构造函数类似于普通函数调用(它执行一些或多或少由参数化的复杂操作),那么我将使用普通函数调用语法。对于默认初始化,我总是使用大括号。首先,我总是确信对象是初始化的,而不管它是一个“真实的”类,它有一个默认的构造函数,它无论如何都会被调用,或者是内置/POD类型。其次,在大多数情况下,它与第一条规则一致,因为默认的初始化对象通常表示“空”对象。在我的经验中,与默认情况下使用大括号相比,可以更一致地应用此规则集,但当所有异常不能被使用或具有与带括号的“正常”函数调用语法不同的含义时,必须显式地记住它们(调用不同的重载)。例如,它与标准库类型(如std::vector:vector<int>&nbsp;a{10,20};&nbsp;&nbsp;&nbsp;//Curly&nbsp;braces&nbsp;->&nbsp;fills&nbsp;the&nbsp;vector&nbsp;with&nbsp;the&nbsp;argumentsvector<int>&nbsp;b(10,20);&nbsp;&nbsp;&nbsp;//Parenthesis&nbsp;->&nbsp;uses&nbsp;arguments&nbsp;to&nbsp;parametrize&nbsp;some&nbsp;functionality,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vector<int>&nbsp;c(it1,it2);&nbsp;//like&nbsp;filling&nbsp;the&nbsp;vector&nbsp;with&nbsp;10&nbsp;integers&nbsp;or&nbsp;copying&nbsp;a&nbsp;range.vector<int>&nbsp;d{};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//empty&nbsp;braces&nbsp;->&nbsp;default&nbsp;constructs&nbsp;vector,&nbsp;which&nbsp;is&nbsp;equivalent &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//to&nbsp;a&nbsp;vector&nbsp;that&nbsp;is&nbsp;filled&nbsp;with&nbsp;zero&nbsp;elements
随时随地看视频慕课网APP
我要回答