为什么列表初始化(使用花括号)比其他方法更好?

本文探讨了C++中列表初始化(使用花括号)的重要性,指出它防止了类型转换可能导致的数据丢失,并且在大多数情况下应优先选择列表初始化。然而,需要注意的是,列表初始化可能会绕过私有或已删除的构造函数,以及在特定情况下可能存在的安全性问题。在初始化对象时,应根据对象的概念意义来决定使用花括号还是普通函数调用语法。
摘要由CSDN通过智能技术生成

本文翻译自:Why is list initialization (using curly braces) better than the alternatives?

MyClass a1 {a};     // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);

Why? 为什么?

I couldn't find an answer on SO, so let me answer my own question. 我找不到关于SO的答案,所以让我回答我自己的问题。


#1楼

参考:https://stackoom.com/question/1EScA/为什么列表初始化-使用花括号-比其他方法更好


#2楼

Basically copying and pasting from Bjarne Stroustrup's "The C++ Programming Language 4th Edition" : 基本上是从Bjarne Stroustrup的“ C ++编程语言第4版”进行复制和粘贴:

List initialization does not allow narrowing (§iso.8.5.4). 列表初始化不允许缩小(第8.5.4节)。 That is: 那是:

  • An integer cannot be converted to another integer that cannot hold its value. 一个整数不能转换为另一个不能保存其值的整数。 For example, char to int is allowed, but not int to char. 例如,允许将char转换为int,但不允许将int转换为char。
  • A floating-point value cannot be converted to another floating-point type that cannot hold its value. 浮点值不能转换为不能保存其值的另一种浮点类型。 For example, float to double is allowed, but not double to float. 例如,允许将float翻倍,但不允许double浮点。
  • A floating-point value cannot be converted to an integer type. 浮点值不能转换为整数类型。
  • An integer value cannot be converted to a floating-point type. 整数值不能转换为浮点类型。

Example: 例:

void fun(double val, int val2) {

    int x2 = val; // if val==7.9, x2 becomes 7 (bad)

    char c2 = val2; // if val2==1025, c2 becomes 1 (bad)

    int x3 {val}; // error: possible truncation (good)

    char c3 {val2}; // error: possible narrowing (good)

    char c4 {24}; // OK: 24 can be represented exactly as a char (good)

    char c5 {264}; // error (assuming 8-bit chars): 264 cannot be 
                   // represented as a char (good)

    int x4 {2.0}; // error: no double to int value conversion (good)

}

The only situation where = is preferred over {} is when using auto keyword to get the type determined by the initializer. 与{}相比,首选=的唯一情况是使用auto关键字获取由初始化程序确定的类型时。

Example: 例:

auto z1 {99};   // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99;   // z3 is an int

Conclusion 结论

Prefer {} initialization over alternatives unless you have a strong reason not to. 除非您有充分的理由,否则将{}初始化优先于替代方案。


#3楼

There are MANY reasons to use brace initialization, but you should be aware that the initializer_list<> constructor is preferred to the other constructors , the exception being the default-constructor. 使用括号初始化有很多原因,但是您应该知道, initializer_list<>构造函数比其他构造函数更可取 ,但默认构造函数除外。 This leads to problems with constructors and templates where the type T constructor can be either an initializer list or a plain old ctor. 这会导致构造函数和模板出现问题,其中T型构造函数可以是初始化列表或简单的旧ctor。

struct Foo {
    Foo() {}

    Foo(std::initializer_list<Foo>) {
        std::cout << "initializer list" << std::endl;
    }

    Foo(const Foo&) {
        std::cout << "copy ctor" << std::endl;
    }
};

int main() {
    Foo a;
    Foo b(a); // copy ctor
    Foo c{a}; // copy ctor (init. list element) + initializer list!!!
}

Assuming you don't encounter such classes there is little reason not to use the intializer list. 假设您没有遇到此类,则没有理由不使用初始化器列表。


#4楼

There are already great answers about the advantages of using list initialization, however my personal rule of thumb is NOT to use curly braces whenever possible, but instead make it dependent on the conceptual meaning: 关于使用列表初始化的好处已经有了很好的答案,但是我个人的经验法则是不要在可能的情况下使用花括号,而应使它依赖于概念上的含义:

  • If the object I'm creating conceptually holds the values I'm passing in the constructor (eg containers, POD structs, atomics, smart pointers etc.), then I'm using the braces. 如果我要创建的对象从概念上讲包含我在构造函数中传递的值(例如,容器,POD结构,原子,智能指针等),那么我正在使用花括号。
  • If the constructor resembles a normal function call (it performs some more or less complex operations that are parametrized by the arguments) then I'm using the normal function call syntax. 如果构造函数类似于常规函数调用(它执行由参数参数化的或多或少的复杂操作),那么我使用的是常规函数调用语法。
  • For default initialization I always use curly braces. 对于默认初始化,我始终使用花括号。
    For one, that way I'm always sure that the object gets initialized irrespective of whether it eg is a "real" class with a default constructor that would get called anyway or a builtin / POD type. 对于这种方式,我始终确保对象被初始化,而无论它是否是带有默认构造函数的“真实”类,无论如何它都会被调用或内置/ POD类型。 Second it is - in most cases - consistent with the first rule, as a default initialized object often represents an "empty" object. 第二,在大多数情况下,它与第一个规则一致,因为默认的初始化对象通常表示“空”对象。

In my experience, this ruleset can be applied much more consistently than using curly braces by default, but having to explicitly remember all the exceptions when they can't be used or have a different meaning than the "normal" function-call syntax with parenthesis (calls a different overload). 以我的经验,可以比默认使用花括号更一致地应用此规则集,但是在不能使用它们或与带有括号的“常规”函数调用语法含义不同时,必须明确记住所有异常(调用其他重载)。

It eg fits nicely with standard library-types like std::vector : 例如,它非常适合标准库类型,例如std::vector

vector<int> a{10,20};   //Curly braces -> fills the vector with the arguments

vector<int> b(10,20);   //Parentheses -> uses arguments to parametrize some functionality,                          
vector<int> c(it1,it2); //like filling the vector with 10 integers or copying a range.

vector<int> d{};      //empty braces -> default constructs vector, which is equivalent
                      //to a vector that is filled with zero elements

#5楼

It only safer as long as you don't build with -Wno-narrowing like say Google does in Chromium. 只要您不使用-Wno-narrowing进行构建(如Google在Chromium中所做的那样),它就更加安全。 If you do, then it is LESS safe. 如果这样做,则安全性较低。 Without that flag the only unsafe cases will be fixed by C++20 though. 如果没有该标志,只有不安全的情况将由C ++ 20修复。

Note: A) Curly brackets are safer because they don't allow narrowing. 注意:A)弯括号比较安全,因为它们不允许变窄。 B) Curly brackers are less safe because they can bypass private or deleted constructors, and call explicit marked constructors implicitly. B)弯括号不安全,因为它们可以绕过私有或已删除的构造函数,并隐式调用显式标记的构造函数。

Those two combined means they are safer if what is inside is primitive constants, but less safe if they are objects (though fixed in C++20) 这两个组合意味着如果内部是原始常量,它们将更安全,但是如果它们是对象,则它们将更不安全(尽管在C ++ 20中已修复)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值