总是用{}初始化对象是好习惯吗?

时间:2015-10-30 20:57:51

标签: c++ c++11 initializer-list

使用新的{}语法初始化对象:

int a { 123 };

有好处 - 您不会声明函数而不是错误地创建变量。我甚至听说应该习惯这样做。但看看会发生什么:

// I want to create vector with 5 ones in it:
std::vector<int> vi{ 5, 1 }; // ups we have vector with 5 and 1.
那是这个好习惯吗?有没有办法避免这样的问题?

2 个答案:

答案 0 :(得分:5)

使用list initialization初始化对象     在适用的地方应该是首选,因为:

  1. 其他好处 list-initialization限制允许的隐式缩小 转换。

    特别禁止:

    • 从浮点类型转换为整数类型
    • long double转换为double或转换为float并从double转换为float,除非来源是 不会发生常量表达和溢出。
    • 从整数类型转换为浮点类型,除非源是可以存储其值的常量表达式 完全在目标类型中。
    • 从整数或无范围枚举类型转换为不能表示原始值的整数类型,除外 其中source是一个常量表达式,其值可以存储 完全在目标类型中。
  2. 另一个好处是免疫most vexing parse
  3. 此外,初始化列表构造函数优先于其他构造函数 可用的构造函数,默认值除外。
  4. 此外,它们可以广泛使用,所有STL容器都有初始化列表构造函数。
  5. 现在关于你的例子,我会说知识带来力量。有一个特定的构造函数用于生成5个向量(即std::vector<int> vi( 5, 1);)。

答案 1 :(得分:4)

Frankly, the subtleties of the various initialization techniques make it difficult to say that any one practice is a "good habit."

As mentioned in a comment, Scott Meyers discusses brace-initialization at length in Modern Effective C++. He has made further comments on the matter on his blog, for instance here and here. In that second post, he finally says explicitly that he thinks the morass of C++ initialization vagaries is simply bad language design.

As mentioned in 101010's answer, there are benefits to brace-initialization. The prevention of implicit narrowing is the main benefit, in my opinion. The "most vexing parse" issue is of course a genuine benefit, but it's paltry--it seems to me that in most cases an incorrect int a(); instead of int a; would probably be caught at compile time.

But there are at least two major drawbacks:

  • In C++11 and C++14, auto always deduces std::initializer_list from a brace-initializer. In C++17, if there's only one element in the initialization list, and = is not used, auto deduces the type of that element; the behavior for multiple elements is unchanged (See the second blog post linked above for a clearer explanation, with examples.) (Edit: as pointed out by T.C. in a comment below, my understanding of the C++17 rules for auto with brace initialization is still not quite right.) All of these behaviors are somewhat surprising and (in mine and Scott Meyers' opinions) annoying and perplexing.
  • 101010's third listed benefit, which is that initialization list constructors are preferred to all other constructors, is actually a drawback as well as a benefit. You've already mentioned that the behavior of std::vector<int> vi{ 5, 1 }; is surprising to people familiar with vector's old two-element constructor. Scott Meyers lists some other examples in Effective Modern C++. Personally, I find this even worse than the auto deduction behavior (I generally only use auto with copy initialization, which makes the first issue fairly easy to avoid).

EDIT: It turns out that stupid compiler-implementation decisions can sometimes be another reason to use brace-initialization (though really the #undef approach is probably more correct).