直接列表初始化和复制列表初始化之间的区别 [英] Differences between direct-list-initialization and copy-list-initialization

查看:465
本文介绍了直接列表初始化和复制列表初始化之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道在C ++ 11和更高版本中以下两种 std :: vector 初始化类型是否有区别。

I would like to know if there is any difference the following two types of std::vector initialization in C++11 and later.

std::vector<int> v1 {1, 2, 3, 4, 5};
std::vector<int> v2 = {1, 2, 3, 4, 5};

这是一个可以正常工作的完整代码示例。

Here is a complete code example that works fine.

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v1 {1, 2, 3, 4, 5};
    std::vector<int> v2 = {1, 2, 3, 4, 5};

    std::cout << v1.size() << '\n';
    std::cout << v2.size() << '\n';
}

我看到两个初始化都导致相同的结果。

I see both initializations leading to identical results.

http://en.cppreference.com/上的示例w / cpp / container / vector 使用第二种,所以让我开始思考这种初始化是否有优势。

The example at http://en.cppreference.com/w/cpp/container/vector uses the second kind, so that got me thinking if this kind of initialization has any advantage.

总的来说,我想要知道一个初始化是否比另一个初始化具有特定的技术优势,或者一个初始化是否被认为是最佳实践,而另一个则没有,以及为什么呢?

In general, I want to know if one initialization has a specific technical advantage over the other, or if one initialization is considered best-practice while the other is not, and if so why.

,我担心的是复制列表初始化是否由于临时对象和复制而产生了额外的开销?

Especially, what I am concerned about is whether the copy-list-initialization has additional overhead due to temporary objects and copying?

推荐答案

List初始化被非正式地称为统一初始化。

List initialization is informally called "uniform initialization" because its meaning and behavior is intended to be the same regardless of how you invoke it.

当然,由于C ++是C ++,所以意向是指它的含义和行为。并非总是会发生。

Of course, C++ being C++, what is "intended" doesn't always happen.

直接列表初始化和复制列表初始化的行为基本上有三个主要区别。第一个是您最常遇到的一个:如果列表初始化将调用标记为 explicit 的构造函数,则如果列表初始化形式为copy-list,则会出现编译错误-初始化。

There are basically three major differences between the behavior of direct-list-initialization and copy-list-initialization. The first is the one you will encounter most frequently: if list initialization would call a constructor marked explicit, then there is a compile error if the list-initialization form is copy-list-initialization.

此行为差异在 [over.match.list] / 1


在复制列表初始化中,如果 explicit 构造函数,初始化格式错误。

In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.

这是重载解析的函数。

第二个主要区别(C ++ 17的新特性)是,给定具有固定基础大小的枚举类型,您可以使用基础类型的值对其执行直接列表初始化。但是您不能从这样的值执行复制列表初始化。因此,枚举e {value}; 有效,但枚举e = {value}; 无效。

The second major difference (new to C++17) is that, given an enum-type with a fixed underlying size, you can perform direct-list-initialization on it with a value of the underlying type. But you cannot perform copy-list-initialization from such a value. So enumeration e{value}; works, but not enumeration e = {value};.

第三个主要区别(也是C ++ 17的新增功能)与 auto 推导中的括号初始列表的行为有关。通常, auto 的行为与模板自变量推导不太明显。但是与模板参数推导不同,可以从大括号初始化列表中初始化 auto

The third major difference (also new to C++17) relates to the behavior of braced-init-lists in auto deduction. Normally, auto behaves not too distinctly from template argument deduction. But unlike template argument deduction, auto can be initialized from a braced-init-list.

如果初始化 auto 变量,使用直接列表初始化且列表中只有一个表达式,编译器将推导该变量为表达式类型:

If you initialize an auto variable using direct-list-initialization with a single expression in the list, the compiler will deduce the variable to be of the type of the expression:

auto x{50.0f}; //x is a `float`.

听起来合理。但是,如果使用copy-list-initialization做完全相同的事情,它将总是推导为 initializer_list< T> ,其中 T 是初始化程序的类型:

Sounds reasonable. But if do the exact same thing with copy-list-initialization, it will always be deduced to an initializer_list<T>, where T is the type of the initializer:

auto x = {50.0f}; //x is an `initializer_list<float>`

非常非常统一。 ;)

值得庆幸的是,如果您在braced-init-list中使用了多个初始化程序,则可以为 auto -直接进行列表初始化推导的变量将始终产生编译错误,而复制列表初始化将给出更长的 initializer_list 。因此,自动推导的直接列表初始化永远不会给出 initializer_list ,而自动推导的副本列表初始化总是会给出。

Thankfully, if you use multiple initializers in the braced-init-list, direct-list-initialization for an auto-deduced variable will always give a compile error, while copy-list-initialization will just give a longer initializer_list. So auto-deduced direct-list-initialization will never give an initializer_list, while auto-deduced copy-list-initialization always will.

有些细微的差别很少影响初始化的预期行为。在这些情况下,单个值的列表初始化将使用复制或直接(非列表)初始化,以适合列表初始化形式。这些情况是:

There are some minor differences that rarely affects the expected behavior of the initialization. These are cases where list-initialization from a single value will use copy or direct (non-list) initialization as appropriate to the list-initialization form. These cases are:


  1. 从与初始化的聚合类型相同的单个值初始化聚合。这会绕过聚合初始化。

  1. Initializing an aggregate from a single value which is the same type as the aggregate being initialized. This bypasses aggregate initialization.

从单个值初始化非类,非枚举类型。

Initializing a non-class, non-enumeration type from a single value.

初始化参考。

不仅这些不这种情况发生得特别频繁,因此它们基本上永远不会真正改变代码的含义。非类类型没有显式构造函数,因此复制和直接初始化之间的区别大部分是学术上的。参考也一样。总的来说,实际上只是关于从给定值执行复制/移动。

Not only do these not happen particularly frequently, they basically never really change the meaning of the code. Non-class types don't have explicit constructors, so the difference between copy and direct initialization is mostly academic. Same goes for references. And the aggregate case is really just about performing a copy/move from a given value.

这篇关于直接列表初始化和复制列表初始化之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆