在C ++ 0x中,非静态数据成员初始值设定项是否会覆盖隐式复制构造函数?

时间:2011-11-21 20:53:00

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

根据与N2628相关的,非静态数据成员初始值设定项可以被显式定义的构造函数覆盖,但它似乎对隐式定义的复制构造函数略显模糊。

特别是,我注意到使用Apple clang 3.0版时,行为会因结构(或类)是否为POD而有所不同。

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

#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版(标签/ Apple / clang-318.0.45)中出现(基于LLVM 3.1svn)。这个版本的clang是作为Lion的Xcode 4.3的一部分发布的。

1 个答案:

答案 0 :(得分:10)

毕竟不是阴影,请参阅标准摘要的重点部分:

关于默认复制/移动构造函数(第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&amp;&amp;,则使用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的brace-or-equalinitializer中的副作用。 —end example ]


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

§12.1

  

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