69

据我所知,在 C++ 中初始化变量有三种方法。

int x = 0;    // C-like initialization
int x (0);    // Constructor initialization
int x {0};    // Uniform initialization

C++11引入了统一初始化,以提供更统一的语法来初始化不同类型的变量,这在C++03中需要不同的语法。

类 C、构造函数和统一初始化之间有什么区别?我应该总是使用统一初始化吗?

4

2 回答 2

73

首先,我建议看一下Herb Sutter的以下演讲,他在其中就该主题提出了一些建议。大括号初始化讨论在23:00 左右开始。

当您谈论原始数据类型时,所有 3 种都会产生相同的结果。我个人更喜欢坚持使用旧int x = 0语法,但这取决于个人喜好。

对于类类型,大括号初始化和老式构造函数初始化不是完全可以互换的。例如:

vector<int> v (100); // Creates a 100-element vector
vector<int> v {100}; // Creates a 1-element vector, holding the value 100.

这是因为std::vector有一个明确定义std::initializer_list为其唯一参数的构造函数。请记住,

auto var = {1, 2};

创建一个std::initializer_list,var作为其标识符。

关于初始化列表的事情是,它们提供了一致性,这是对之前可用的内容的可喜变化。例如,如果您要在 C++ 中初始化一个数组,您将使用:

int arr[] = {1, 2, 3, 4};

但是,如果你想vector<int>用相同的元素初始化 a,你要么必须:

  1. 先初始化上面的arr,然后通过arrandarr + 4
  2. 单独或循环创建向量和 push_back() 元素。

使用 C++11,您可以使用

vector<int> v = {1, 2, 3, 4}; // Same syntax. Nice! Note that the = is optional

大括号初始化有用的另一个例子是它为 C++最令人头疼的 parse提供了一种解决方法。从谈话中,假设我们有两个类,originextents,它们的实例可以被传递来构造另一个类型的对象rectangle。以下声明:

rectangle w(origin(), extents());

不允许您使用和临时创建rectangle对象,因为该语句被解析为函数声明。啧啧。所以通常,你必须这样做:originextents

origin  o;
extents e;
rectangle w(o, e);

通过大括号初始化,您可以动态创建它们,并且

rectangle w {origin(), extents()};

将按预期工作,即传递给构造函数,该构造函数重载了一个origin对象作为它的第一个参数,一个extents对象作为第二个参数。

该规则适用于对象,除非您有理由不这样做,否则请使用大括号初始化。

于 2014-07-25T11:01:33.350 回答
18

c-like、构造函数和统一初始化之间有什么区别?

对于像这样的原始类型int,没有实际区别;所以让我们考虑一个类类型T

第一种样式相当于

T x(T(0));

从初始化表达式创建一个临时对象,然后x通过移动或复制它进行初始化。在实践中,移动或复制将被省略,这样结果与第二种样式相同;唯一的区别是,如果没有可访问的副本或移动构造函数,第一个将失败。

第二个使用带有一个参数的构造函数直接初始化对象,如果没有合适的构造函数则给出错误。

第三个取决于可用的构造函数。

  • 如果有一个构造函数std::initializer_list,它会使用它;
  • 否则,如果有一个构造函数采用合适类型的单个参数,它会使用它;
  • 否则,如果它是具有一个成员的聚合(没有构造函数),则将该成员初始化为零;
  • 否则,这是一个错误。

我应该总是使用统一初始化吗?

不,有时您需要函数式初始化来区分initializer_list构造函数和采用其他参数类型的构造函数。例如:

std::vector<int> v1(10, 42);  // 10 elements with value 42
std::vector<int> v2{10, 42};  // 2 elements with values 10 and 42

您也不应该将其称为“统一初始化”,因为它在任何有意义的意义上都不是“统一”。官方术语是“大括号初始化”。

于 2014-07-25T11:01:03.437 回答