如何调用clang ++或g ++来完全复制两个不同标准版本中的需求

时间:2014-01-09 14:34:07

标签: c++ c++11 compiler-warnings language-lawyer value-initialization

我试图确定N3337§8.5p7(C ++ 11)和N3797§8.5p8(后C ++ 11)之间的差异,这些差异涉及价值初始化。

N3337§8.5p7

  

对T类型的对象进行值初始化意味着:

     
      
  • 如果T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9节),那么T的默认构造函数   被调用(如果T无法访问,则初始化是错误的   默认构造函数);
  •   
  • 如果T是一个(可能是cv限定的)非联合类类型而没有用户提供的构造函数,那么该对象是零初始化的,如果   T的隐式声明的默认构造函数是非平凡的   构造函数被调用。
  •   
  • 如果T是数组类型,则每个元素都是值初始化的;
  •   
  • 否则,该对象为零初始化。
  •   
     

值初始化的对象被视为构造并因此受到约束   适用于“建造”的本国际标准的规定   对象,“构造函数已完成的对象”等,甚至   如果没有为对象的初始化调用构造函数。

N3797§8.5p8:

  

对T类型的对象进行值初始化意味着:

     
      
  • 如果T是一个(可能是cv-quali fi ed)类类型(第9条),没有默认构造函数(12.1)或默认构造函数   用户提供或删除,然后该对象被默认初始化;
  •   
  • 如果T是(可能是cv-quali fi ed)类类型而没有用户提供或删除的默认构造函数,则该对象为零初始化   并检查默认初始化的语义约束,   如果T有一个非平凡的默认构造函数,那么对象就是   缺省初始化;
  •   
  • 如果T是数组类型,则每个元素都是值初始化的;
  •   
  • 否则,该对象为零初始化。
  •   
     

值初始化的对象被视为构造和   因此,本国际标准的规定适用于   “构造”对象,“构造函数具有的对象”   完成,“等等,即使没有为对象调用构造函数   初始化。

鉴于这两条规则,下面的代码段会给出不同的结果:

#include <iostream>
struct Base {
    int i;

    Base(int i):i(i) {}
    Base():i(10) {}
};

struct Derived : public Base {
    int j;

    Derived(int j):Base(j), j(j) {}
    Derived()=default;
};

int main() {
    Derived d{};
    std::cout << "d.i = " << d.i << "  " << "d.j = " << d.j << '\n';
}

如下:

  1. 根据N3337,调用Derived的默认构造函数,因为Derived具有用户提供的构造函数。 Derived的默认构造函数调用Base默认构造函数,初始化Derived::i = 10,保留Derived::j一致。
  2. 从N3797开始,由于Derived没有用户提供的默认构造函数,也没有删除的默认构造函数,因此第二个项目符号点适用。也就是说,Derived是零初始化的,即Derived::iDerived::j都用0初始化,对象d默认初始化,离开{{1} }。
  3. 虽然我对Unixs的了解最少,但我一直在尝试复制这两种情况,在Coliru中通过反复试验使用编译器clang ++和g ++的不同标志,但无济于事。到目前为止的结果,所有打印Derived::i = 10 都没有警告

1 个答案:

答案 0 :(得分:3)

OP中的程序无法区分d.j是否被初始化为0或者它是否未初始化且恰巧恰好为0.如果要在内存中创建相关的Derived对象,这将是明确的已经初始化为已知的非零值,比如放置新的:

 Derived d{42};        // d.i and d.j are both 42.
 ::new (&d) Derived{}; // d.i is 0, d.j is 0 per N3797 or 42 per N3337.

作为dyp says in his comment,编译器通常会跟踪由于标准中的缺陷(而不是新功能)而导致的更改,并将它们包含在对特定标准修订版的支持中。鉴于标准不断变化,可能没有编译器能够完全编译完全任何给定标准文档中指定的语言。当你告诉,例如,clang 3.4编译C ++ 11时,它实际实现的语言是“C ++ 11的一部分加上我们已经实现的相关缺陷解决方案(IIRC全部为3.4)及时发布3.4版本。“

OP询问的值初始化措辞的特定更改发生在Core Working Group (CWG) Defect Report (DR) number 1301的解决方案中,该解决方案也解决了DR1324DR1368。作为缺陷解决方案,编译器将有理由实施更改。

使用各种编译器和版本进行分析(主要由OP执行)演示:

总之,没有办法强制编译器按照指定执行完全,但我们通常可以通过仔细分析来确定正在发生的事情。