【问题标题】:Are () and {} always equivalent when used for initialization with "new"?当使用“new”进行初始化时,() 和 {} 是否总是等价的?
【发布时间】:2015-05-03 10:25:40
【问题描述】:

有一个帖子处理parentheses or not after the type name 使用new 时。但是这个呢:

如果'Test'是一个普通的类,有什么区别:

Test* test = new Test();
// and
Test* test = new Test{};

此外,假设Test2 有一个Value 类型参数的构造函数,它是否总是等价于写:

Value v;
Test2 *test2 = new Test(v);
// and
Test2 *test2 = new Test{v};

【问题讨论】:

    标签: c++ c++11 constructor initialization new-operator


    【解决方案1】:

    涉及std::initializer_list<>的上下文可能存在差异,例如:

    案例 1 - (){}

    #include <initializer_list>
    #include <iostream>
    using namespace std;
    
    struct Test2 {
        Test2(initializer_list<int> l) {}
    };
    
    int main() {
        Test2* test3 = new Test2(); // compile error: no default ctor
        Test2* test4 = new Test2{}; // calls initializer_list ctor
    }
    

    案例 2:(v){v}

    struct Value {
    };
    
    struct Test3 {
        Test3(Value v) {}
        Test3(initializer_list<Value> v) {}
    };
    
    int main() {
        Value v;
        Test3* test5 = new Test3(v); // calls Test3(Value)
        Test3* test6 = new Test3{v}; // calls Test3(initializer_list<Value>)
    }
    

    正如 Meyers 和其他人所说,使用 STL 时也有很大的不同:

        using Vec = std::vector<int>;
        Vec* v1 = new Vec(10); // vector of size 10 holding 10 zeroes
        Vec* v2 = new Vec{10}; // vector of size 1 holding int 10
    

    而且不仅限于std::vector

    在这种情况下没有区别(initializer_list ctor 被忽略)

    #include <initializer_list>
    #include <iostream>
    using namespace std;
    
    struct Test {
        Test() {}
        Test(initializer_list<int> l) {}
    };
    
    int main() {
        Test* test1 = new Test(); // calls default ctor
        Test* test2 = new Test{}; // same, calls default ctor
    }
    

    在这种情况下还有一个众所周知的区别

    void f() {
        Test test{};
        Test test2();
    }
    

    其中testTest 类型的默认初始化对象,test2 是函数声明。

    【讨论】:

    • 这已经在这个问题的“后续行动”的答案中说明了。
    • 你说得对 - 如果初始化程序是 braced-init-list,direct-initialisation 本身会遵循 list-initialisation .
    • Scott Meyers Effective Modern C++ 中有专门的项目。
    • 是的,但是 Meyers 确实省略了这种情况 - 当 () 或 {} 中没有任何内容时
    【解决方案2】:

    不!

    new-initializer 可以采用以下形式:

    新的初始化器
    ( 表达式列表opt)
    支撑初始化列表

    还有:

    [C++11: 5.3.4/15]: 创建T 类型对象的new-expression 将该对象初始化如下:

    • 如果省略 new-initializer,则对象为 default-initialized (8.5);如果不执行初始化,则该对象具有不确定的值。
    • 否则,new-initializer 会根据 8.5 的初始化规则来解释 direct-initialization

    还有:

    [C++11: 8.5/15]:表单中发生的初始化

    T x(a);
    T x{a};
    

    以及在 new 表达式 (5.3.4)、static_cast 表达式 (5.2.9)、函数符号类型转换 (5.2.3) 以及基类和成员初始化程序 (12.6.2) 中称为 直接初始化.

    还有:

    [C++11: 8.5/16]: 初始化器的语义如下。 [..]

    • 如果初始值设定项是(非括号)braced-init-list,则对象或引用是 list-initialized (8.5.4)。
    • [..]
    • 如果初始化器是(),则对象是值初始化的
    • [..]
    • 如果初始化是 direct-initialization,或者如果是 copy-initialization,其中源类型的 cv 非限定版本与相同的类,或者派生类,目的地的类,构造函数都考虑在内。列举了适用的构造函数(13.3.1.3),最好的 一个是通过重载决议(13.3)选择的。调用如此选择的构造函数来初始化对象,使用初始化表达式或表达式列表作为其参数。如果没有构造函数适用,或者重载决议不明确,则初始化格式错误。
    • [..]

    因此,您看,在这种情况下(以及其他一些情况),两者都被定义为 直接初始化,但进一步的规则意味着根据您是否使用可能会发生不同的事情(){} 以及初始化程序是否为空。

    考虑到 list-initialisation 的规则,我不会在这里重现,这两个初始化器具有基本相同的效果 if T 没有构造函数采用std::initializer_list&lt;&gt;.

    【讨论】:

    • ...和 ​​if T 不是聚合。
    【解决方案3】:

    一般的答案是否定的。使用花括号初始化列表作为初始化器将首先尝试解析为采用std::initializer_list 的构造函数。举例说明:

    #include <iostream>
    #include <vector>
    int main() {
      auto p = new std::vector<int>{1};
      auto q = new std::vector<int>(1);
      std::cout << p->at(0) << '\n';
      std::cout << q->at(0) << '\n';
    }
    

    注意列表初始化的语义(引自cppreference):

    • 所有将 std::initializer_list 作为唯一参数或作为第一个参数(如果其余参数有)的构造函数 默认值,由重载决议检查和匹配 针对 std::initializer_list 类型的单个参数
    • 如果前一阶段未产生匹配,则 T 的所有构造函数都参与针对 由支撑初始化列表的元素组成,具有限制 只允许非缩小转换。如果这个阶段 生成一个显式构造函数作为 a 的最佳匹配 复制列表初始化,编译失败(注意,简单 复制初始化,完全不考虑显式构造函数)

    【讨论】:

    • 我认为它们在第一种情况下也不同
    • @sp2danny 列表初始化的语义非常复杂。不同版本的 C++ 也有不同的说法。无论如何,我决定保留现在的答案,因为它是日常编程中最相关的部分,人们应该熟悉它。但也欢迎对此答案进行编辑以使其更准确。
    猜你喜欢
    • 1970-01-01
    • 2016-03-03
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多