用于初始化单个变量的C ++样式

时间:2013-06-14 16:01:59

标签: c++ c++11 coding-style initialization

初始化自动管理的简单变量而不是通过赋值时,有几种不同的样式。我想知道是否有任何具体的理由支持一个而不是另一个或只是风格问题。

使用括号很有吸引力,因为它感觉类似于实例化对象

double answer(42.0);
ComplexNumber i(0,1);

虽然使用大括号很有吸引力,因为它感觉类似于初始化容器

double answer{42};
std::vector<double> i{0,1};
double i2[] = {0,1};

有没有什么特别的理由支持一种风格而不是另一种?

3 个答案:

答案 0 :(得分:4)

请看这里:GotW #1 : Variable Initialization。这是H. Sutter的答案的详细描述。

小时。 Sutter在一般意义上讲述了可变初始化的新旧风格。

根据您的开始主题背景,下面显示了该文章的快速概要。


这一对

double answer(42.0); // (1)
double answer{42};  // (2)

实际上,类似于下一个初始化示例:

widget w(x);                // (d)
widget w{x};                // (e)

这些都是直接初始化。但请注意,语法{x}会创建initializer_list。如果widget的构造函数带有initializer_list,则首选构造函数;否则,如果widget的构造函数采用任何类型x(可能包含转换),则使用该构造函数。

有两个主要差异使(2,e)优于(1,d):

  • 首先,语法(2,e)是明确的,避免了“烦恼的解析”。如果x是类型名称,那么(1,d)是函数声明,即使在作用域中还有一个名为x的变量(见上文),而(2,e)永远不是功能声明。
  • 其次,语法(2,e)更安全,因为它不允许缩小(a.k.a。“有损”)转换,否则这些转换允许某些内置类型。考虑:

    int i1( 12.345 ); // ok: toss .345, we didn't like it anyway

    int i2{ 12.345 }; // error: would be lossy implicit narrowing

下一对

ComplexNumber i(0,1); // (3)
std::vector<double> i{0,1}; // (4)

与复杂对象的初始化相关联。两者看起来完全相同,但第二个帮助我们避免“烦恼的解析”,如:

ComplexNumber       w( real(), img() );       // oops, vexing parse 

除此之外,这种方式使代码更清晰(如果我们使用initializer_list,则更清楚的是初始化), 而且,在某些情况下,减轻语法,例如:

draw_rect({ origin, selection });                  // C++11

Sutter guildeline是:更喜欢使用{ }初始化,例如vector<int> v = { 1, 2, 3, 4 };auto v = vector<int>{ 1, 2, 3, 4 };,因为它更一致,更正确,并且避免了解旧式陷阱一点都不在单参数情况下,您希望仅查看=符号,例如int i = 42;和auto x = anything;省略括号是好的。

我们可以使用()-initialization来显式调用特殊构造函数。

答案 1 :(得分:2)

添加到Borisanswer还有另一个陷阱,以避免在Herb的博客文章中没有提及。

以下代码是非法的:

#include <initializer_list>

int main() {
  auto i{42}; // not the same as 'auto i(42);'
  ++i;
}

gcc 4.7.2引发的错误消息是:

  
    

错误:'++ i'中的'operator ++'不匹配

  

原因是auto推断{42}的类型为std::inilializer_list<int>,而不是int,正如许多人所能相信的那样。 operator ++没有std::initializer_list<int>因此错误。如果您将{42}替换为(42),则代码编译正常。

答案 2 :(得分:1)

GotW #93有一个非常有趣的理由,用auto声明所有内容。