类c、构造函数和统一初始化之间的区别是什么?



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

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

统一初始化是c++ 11引入的,目的是为初始化不同类型的变量提供更统一的语法,这在c++ 03中需要不同的语法。

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

首先,我建议大家看一下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>,则必须:

  1. 先初始化上述arr,然后传递arrarr + 4
  2. 分别创建vector和push_back(),或者在循环中创建元素。

在c++ 11中,您可以使用

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

大括号初始化的另一个有用的实例是,它为c++中最令人烦恼的解析提供了一个解决方案。从谈话中,假设我们有两个类,originextents,它们的实例可以被传递来构造另一个类型为rectangle的对象。下面的语句:

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

不允许您使用originextents临时创建rectangle对象,因为该语句被解析为函数声明。啧啧啧啧。通常,你需要输入:

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

使用大括号初始化,您可以动态地创建它们,而

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

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

类c、构造函数和统一初始化之间的区别是什么?

对于像int这样的基本类型,没有实际的区别;因此,让我们考虑一个类类型为T

第一种样式相当于

T x(T(0));

从初始化表达式创建一个临时对象,然后通过移动或复制来初始化x。在实际操作中,将移或复制的部分省略掉,使其结果与第二种风格相同;唯一的区别是,如果没有可访问的复制或移动构造函数,第一个操作将失败。

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

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

  • 如果有一个构造函数取std::initializer_list,它使用;
  • 否则,如果有一个构造函数接受一个合适类型的参数,它使用;
  • 否则,如果它是只有一个成员的聚合(没有构造函数),则该成员初始化为0;

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

。有时需要函数式初始化来区分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

你也不应该称它为"统一初始化",因为它在任何意义上都不是"统一"的。官方术语是"大括号初始化"

最新更新