代码之家  ›  专栏  ›  技术社区  ›  Cewu00

在这个构造函数初始化器列表中使用()和{}有什么区别?(C++)[重复]

  •  -1
  • Cewu00  · 技术社区  · 3 年前

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

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

    对以下内容进行了统一初始化 C++11 为初始化不同类型的变量提供更统一的语法,这在 C++03 .

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

    0 回复  |  直到 5 年前
        1
  •  74
  •   Nasser Al-Shawwa    10 年前

    首先,我建议你看看 following talk 赫伯·萨特(Herb Sutter)在文章中对这一主题提出了一些建议。支架初始化讨论开始于 around 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};
    

    创建a std::initializer_list ,与 var 作为其标识符。

    初始化器列表的特点是它们提供了一致性,这与之前的情况相比是一个受欢迎的变化。例如,如果你要在C++中初始化一个数组,你可以使用:

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

    但是,如果你想初始化一个 vector<int> 对于相同的元素,您必须:

    1. 首先初始化上述arr,然后传递 arr arr + 4
    2. 创建向量,并将元素单独或循环使用push_back()。

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

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

    大括号初始化有帮助的另一个例子是,它为C++提供了一种解决方法 most vexing parse 根据谈话内容,假设我们有两节课, origin extents ,可以传递其实例来构造另一个类型的对象 rectangle .以下声明:

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

    不允许您创建 矩形 对象使用 起源 范围 temporaries,因为该语句被解析为函数声明。Tsk-Tsk。因此,通常情况下,您必须执行以下操作:

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

    通过支架初始化,您可以动态创建它们,以及

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

    将按预期工作,即传递给重载了 起源 对象作为第一个参数和 范围 对象作为第二。

    规则是对于对象,使用大括号初始化,除非你有理由不这样做。

        2
  •  18
  •   Mike Seymour    10 年前

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

    对于原始类型,如 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
    

    你也不应该称之为“统一初始化”,因为它在任何有意义的意义上都不是“统一的”。官方术语是“支架初始化”。