关于C++标准中的第12.7p3段,我有以下问题

Ale*_*der 10 c++ standards constructor implicit-conversion c++11

  1. 本条款施加的限制可以避免哪些具体问题12.7p3(见下段第一部分)?

  2. 12.7p3(见下文)所示的例子中,为什么X(this)被认为是定义的?是因为X不在路上E C D B A吗?

    struct A { };
    struct B : virtual A { };
    struct C : B { };
    struct D : virtual A { D(A*); };
    struct X { X(A*); };
    struct E : C, D, X {
    E() : D(this),  // undefined: upcast from E* to A*
                    // might use path E* - D* - A*
                    // but D is not constructed
                    // D((C*)this), // defined:
                    // E* - C* defined because E() has started
                    // and C* - A* defined because
                    // C fully constructed
          X(this) { // defined: upon construction of X,
                    // C/B/D/A sublattice is fully constructed
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)
  3. 请在下面的段落开头找到12.7p3:

显式或隐式地将引用类X的对象的指针(glvalue)转换为指向X的直接或间接基类B的指针(引用),构造X及其所有直接或间接基础的构造直接或间接从B派生的应该已经开始并且这些类的销毁不应该完成,否则转换会导致不确定的行为.

如果说X上面提到的所有直接和间接基础的集合都不包括在内B,并且正因为如此,下面的代码是明确定义的,尽管这Base是直接的基础Derived并且尚未开始,这是正确的吗?

struct Base{ Base(Base*); };

struct Derived : Base {
    Derived() : Base(this) {};
};
Run Code Online (Sandbox Code Playgroud)

Mik*_*son 6

12.7p3规定的限制可以避免哪些具体问题(见下段第一部分)?

这些问题与以下事实有关:在某些时候,必须为派生类初始化虚拟指针(虚拟表或虚拟基类).这是在"初始化列表"期间(即,在构造函数体开始之前)发生的初始化,通常在构造基类之后(例如,在构造基类B之后,虚拟表指针和可能的虚拟基指针)为类X设置,然后初始化数据成员,然后构造函数的主体开始).通常,在初始化这些指针之前执行向上转换将产生未定义的行为,因为无法对虚拟基础执行所需的指针查找,或者无法正确设置虚拟表指针以正确调用虚函数.

在12.7p3(见下文)中显示的示例中,为什么X(this)被认为是定义的?是因为X不在路径ECDBA中吗?

因为基类构造函数按它们出现在类声明中的顺序调用(即,struct E : C, D, X {).因为基类C和D都是构造的,所以它们的公共虚拟基类A当然也是构造的.并且因为X不从类继承A,这意味着在此时执行从类E到类的转换时存在完全构造且明确的路径A.这就是为什么这条线是明确定义的.

如果说上面提到的X的所有直接和间接基数的集合都不包括B是正确的,并且由于这个原因,下面的代码是明确定义的,尽管Base是Derived的直接基础并且还没有没有开始?

我不确定我是否按照你的解释,但我可以告诉你,你展示的代码没有明确定义.当Base通过强制转换Derived* this来调用构造函数时,Base*派生类中的基类对象尚未构造,因此,未定义强制转换.

这个代码有意义的唯一方法是,如果层次结构中没有涉及虚函数或虚拟基类,在这种情况下,由于this指向基类的指针已经隐式地发送到基类,因此不需要这样的代码.基类构造函数.