• C++统一初始化和初始化列表


    一直对C++初始化使用圆括号和花括号的区别有所疑惑,参考书籍和博客简单总结一下


    常见的初始化操作

    对于一个基础数据类型进行初始化,比如 int

    int x(0);
    int y = 0;
    int z{0};
    
    • 1
    • 2
    • 3

    对于用户定义的类型:

    Foo foo1; // default construction
    Foo foo2 = foo1; // equivalent to Foo foo2(foo1)
    foo1 = foo2; // assignment operation, call operator= function
    
    • 1
    • 2
    • 3

    统一初始化(Uniform Initialization)

    C++11之前,初始化一个变量或一个对象,可以使用圆括号()、花括号{} 以及赋值运算符。这就会对初学者产生一定疑惑(具体应该使用哪一种??)。对此,C++11 引入了统一初始化的概念,即对于任意初始化,可以使用一个统一的语法,一个花括号 {},举个栗子:

    int values[] {1, 2, 3}; // initialize int array
    std::vector<int> v{2, 3, 5, 7, 11, 13, 17}; // initialize vector
    std::vector<std::string> cities{"Berlin", "New York", "London", "Braunschweig", "Cairo", "Cologne"}; // implicit conversion: const char * => std::string
    std::complex<double> c{4.0, 3.0}; // equivalent to c(4.0, 3.0)
    
    • 1
    • 2
    • 3
    • 4

    一个初始化列表强迫进行值初始化,基础数据类型初始化为0,指针类型初始化为 nullptr

    int i; // i has undefined value
    int j{}; // j is initialized by 0
    int* p; // p has undefined value
    int* q{}; // q is initialized by nullptr
    
    • 1
    • 2
    • 3
    • 4

    需要注意的是,如果存在收缩转换(narrowing),即精度减小,那么不能使用统一初始化:

    int x1(5.3); // OK, but OUCH: x1 becomes 5
    int x2 = 5.3; // OK, but OUCH: x2 becomes 5
    int x3{5.0}; // ERROR: narrowing
    int x4 = {5.3}; // ERROR: narrowing
    char c1{7}; // OK: even though 7 is an int, this is not narrowing
    char c2{99999}; // ERROR: narrowing (if 99999 doesn’t fit into a char)
    std::vector<int> v1 { 1, 2, 4, 5 }; // OK
    std::vector<int> v2 { 1, 2.3, 4, 5.6 }; // ERROR: narrowing doubles to ints
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    初始化列表(Initializer Lists)

    为了支持用户定义类型的初始化列表,C++11 提供了模板类 std::initializer_list<>。其可被用于支持使用一列值进行初始化或对一列值进行处理。例如:

    void print (std::initializer_list<int> vals)
    {
    for (auto p=vals.begin(); p!=vals.end(); ++p) { // process a list of values
    std::cout << *p << "\n";
    }
    }
    print ({12,3,5,7,11,13,17}); // pass a list of values to print()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当使用统一初始化时,如果构造函数同时匹配指定数量的构造函数以及使用初始化列表的构造函数,优先选择使用初始化列表的构造函数:

    class P
    {
    public:
    P(int,int);
    P(std::initializer_list<int>);
    };
    P p(77,5); // calls P::P(int,int)
    P q{77,5}; // calls P::P(initializer_list)
    P r{77,5,42}; // calls P::P(initializer_list)
    P s = {77,5}; // calls P::P(initializer_list)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果构造函数为显示构造函数,那么不能使用 = 语法进行初始化,因为不能进行隐式转换:

    class P
    {
    public:
    P(int a, int b) {
    ...
    }
    explicit P(int a, int b, int c) {
    ...
    }
    };
    P x(77,5); // OK
    P y{77,5}; // OK
    P z {77,5,42}; // OK
    P v = {77,5}; // OK (implicit type conversion allowed)
    P w = {77,5,42}; // ERROR due to explicit (no implicit type conversion allowed)
    
    void fp(const P&);
    fp({47,11}); // OK, implicit conversion of {47,11} into P
    fp({47,11,3}); // ERROR due to explicit
    fp(P{47,11}); // OK, explicit conversion of {47,11} into P
    fp(P{47,11,3}); // OK, explicit conversion of {47,11,3} into P
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    类似地,使用一个初始化列表的显示构造函数,禁用隐式转换,对于0个、1个或多个初值。

    相比于使用圆括号的一个优势,比如当我们使用带参构造函数可以使用如下语法:

    Foo foo1(10); // call Foo constrution with arguments
    
    • 1

    但使用类似语法调用无参构造函数时,却是声明了个函数,而不是创建对象:

    Foo foo2(); // declare a foo2 function without arguments and return Foo object
    Foo foo2; // foo2 is a default initialized object
    
    • 1
    • 2

    我们可以使用花括号来解决这个歧义,因为花括号无法声明为函数

    Foo f2{}; // no ambiguity
    
    • 1
  • 相关阅读:
    基于最小二乘支持向量机(LS-SVM)进行分类、函数估计、时间序列预测和无监督学习附Matlab代码
    rust学习——操作字符串、字符串转义、操作UTF8-字符串 (操作中文字符串)
    细胞实验中的对照给药
    推荐几个程序员必逛的个人技术博客网站
    GAN生成哆啦A梦,亲测疯狂训练50000epoch的效果,俺的菜菜电脑吃不消
    Nginx实战:代理服务-反向代理
    【第十章】认识与学习BASH
    WMS之添加View
    [源码解析] TensorFlow 分布式之 MirroredStrategy 分发计算
    mysql忘记密码的修改方式
  • 原文地址:https://blog.csdn.net/weixin_44491423/article/details/133703518