【问题标题】:In C++0x, do non-static data member initializers override the implicit copy constructor?在 C++0x 中,非静态数据成员初始化器会覆盖隐式复制构造函数吗?
【发布时间】:2011-11-21 20:53:00
【问题描述】:

根据与 相关的N2628,非静态数据成员初始化程序可以被显式定义的构造函数覆盖,但对于隐式定义的复制构造函数似乎有点模糊。

特别是,我注意到在 Apple clang 3.0 版中,行为会根据结构(或类)是否为 POD 而有所不同。

以下程序返回输出“1”,这表明复制构造函数忽略右侧,而是替换新的非静态数据成员初始值设定项(在本例中,X 的布尔真值::一种)。

#include <iostream>
#include <string>

struct X
{
    std::string string1;
    bool a = true;
};

int main(int argc, char *argv[])
{
    X x;
    x.a = false;
    X y(x);
    std::cout << y.a << std::endl;
}

但是,令人困惑的是,如果您注释掉 string1:

    // std::string string1;  

然后行为按我的预期工作(输出为“0”),大概是因为没有隐式生成的复制构造函数,因此数据被复制

C++0x 规范是否真的建议允许隐式定义的复制构造函数复制右侧的内容?这不是不太有用和不直观吗?我发现非静态成员初始化器功能非常方便,但如果这是正确的行为,那么我将明确避免使用该功能,因为它的行为很棘手且不直观。

请告诉我我错了吗?

更新:此错误已在 Clang 源代码库中修复。看到这个revision

更新:此错误在 Apple clang 3.1 版 (tags/Apple/clang-318.0.45) 中已修复(基于 LLVM 3.1svn)。此版本的 clang 作为 Xcode 4.3 for Lion 的一部分分发。

【问题讨论】:

    标签: c++0x c++ c++11 clang default-copy-constructor


    【解决方案1】:

    毕竟它并不模糊,请参阅标准摘录中突出显示的部分:

    关于默认复制/移动构造函数的部分(第 12.8 节)有点冗长,无法完整引用。低调是带有初始化器的非静态成员字段仍然被默认的复制/移动构造函数简单地复制

    第 12.8 节:

    -6。非联合类 X 的隐式定义的复制/移动构造函数执行成员复制/移动 其基地和成员。 [ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ] 初始化顺序与初始化顺序相同 用户定义的构造函数中的基数和成员数(​​见 12.6.2)。设 x 是 构造函数,或者,对于移动构造函数,引用参数的 xvalue。每个基础或非静态数据 成员以适合其类型的方式复制/移动:

    • 如果成员是一个数组,每个元素直接用x对应的子对象初始化;
    • 如果成员 m 具有右值引用类型 T&&,则使用 static_cast(x.m) 直接初始化它;
    • 否则,基址或成员将直接使用 x 的相应基址或成员进行初始化。
      虚拟基类子对象只能由隐式定义的复制/移动构造函数初始化一次

    这是引用的示例:

    struct A {
        int i = /* some integer expression with side effects */;
        A(int arg) : i(arg) { }
        // ...
    };
    

    A(int) 构造函数将简单地将 i 初始化为 arg 的值,并且 i 的大括号或均衡器中的副作用不会发生。 —end example ]


    为了完整起见,默认构造函数的相应部分:

    § 12.1

    -6。当 odr-used (3.2) 创建其类类型 (1.8) 的对象或在其第一次显式默认后,默认构造函数被默认且未定义为已删除的默认构造函数被隐式定义
    隐式定义的默认构造函数执行类的一组初始化,这些初始化将由用户编写的该类的默认构造函数执行,没有 ctor-initializer (12.6.2) 和空 复合语句。如果该用户编写的默认构造函数格式不正确,则程序格式错误。
    如果该用户编写的默认构造函数满足 constexpr 构造函数(7.1.5)的要求, 隐式定义的默认构造函数是 constexpr。在默认的默认构造函数之前 类是隐式定义的,其基类 及其非静态的所有非用户提供的默认构造函数 数据成员 应已被隐式定义。 [注意:隐式声明的默认构造函数 有一个异常规范(15.4)。
    显式默认定义可能具有隐式异常规范, 见 8.4。 —end note ]

    【讨论】:

    • 有趣。这是参考默认的 copy-constructor 吗?
    • @DavidRodríguez-dribeas、@Kleist、@WillBradley Gee,偷看,我们今晚是不是不耐烦的人群:) 已添加
    • 谢谢。那么,Apple clang 3.0 版中的行为似乎是一个错误。作为参考,我尝试在 gcc 版本 4.6.1 中编译此代码,它返回以下错误,“test.cpp:7:11: sorry, unimplemented: non-static data member initializers”
    • @WillBradley 如果你还没有,记得提交错误llvm.org/bugs
    • @barnes53:我就这个话题提交了llvm.org/bugs/show_bug.cgi?id=11418。感谢您的链接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    相关资源
    最近更新 更多