Подтвердить что ты не робот

Что касается параграфа 12.7p3 в Стандарте С++, у меня есть следующие вопросы

  • Каковы конкретные проблемы, которые следует избегать с ограничениями, налагаемыми этим предложением 12.7p3 (см. первую часть параграфа ниже)?

  • В примере, показанном в 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
        }
    };
    
  • Ниже приводится параграф 12.7p3:

Чтобы явно или неявно преобразовать указатель (glvalue), ссылающийся на объект класса X с указателем (ссылкой) на прямой или косвенный базовый класс B из X, построение X и построение всех его прямых или косвенных оснований, которые прямо или косвенно получают от B, и уничтожение этих классов должно не завершены, в противном случае результат преобразования в undefinedповедение.

Можно ли сказать, что множество всех прямых и косвенных оснований X, упомянутых выше, не включает B, и из-за этого код ниже хорошо определен, несмотря на то, что Base является прямой базой Derived и еще не началось?

struct Base{ Base(Base*); };

struct Derived : Base {
    Derived() : Base(this) {};
};
4b9b3361

Ответ 1

Каковы конкретные проблемы, которые следует избегать с ограничениями, налагаемыми этим пунктом 12.7p3 (см. первую часть параграфа ниже)?

Проблемы связаны с тем, что в какой-то момент виртуальные указатели (к виртуальной таблице или виртуальным базовым классам) должны быть инициализированы для производного класса. Это инициализация, которая возникает во время "списка инициализации" (т.е. До начала тела конструктора), как правило, сразу после создания базового класса (например, после того, как построен базовый класс B, указатель виртуальной таблицы и, возможно, виртуальный базовый указатель для класса X, а затем элементы данных инициализируются, а затем начинается тело конструктора). В общем случае выполнение up-cast перед инициализацией этих указателей приведет к поведению undefined либо потому, что требуемый поиск указателя не может быть выполнен для виртуальной базы, либо указатель виртуальной таблицы не будет корректно установлен для виртуальных функций правильно называется.

В примере, показанном в 12.7p3 (см. ниже), почему X (это) считается определенным? Это потому, что X не находится на пути E C D B A?

Потому что конструкторы базового класса вызывают в порядке их появления в объявлении класса (т.е. struct E : C, D, X {). Так как базовые классы C и D построены, их общий виртуальный базовый класс A, безусловно, также построен. И поскольку X не наследует от класса A, это означает, что в данный момент существует полностью построенный и недвусмысленный путь при выполнении cast из класса E в класс A. Вот почему эта строка четко определена.

Правильно ли говорить, что множество всех прямых и косвенных оснований X, упомянутых выше, не включает B, и из-за этого код ниже хорошо определен, несмотря на то, что Base является прямой базой Derived и еще не началось?

Я не уверен, что следую вашим объяснениям, но могу вам сказать, что код, который вы показали, не определен. При вызове конструктора Base путем отбрасывания Derived* this до Base* объект базового класса в производном классе еще не сконструирован, и, таким образом, литье undefined.

Единственный способ, которым этот код мог бы иметь смысл, - это отсутствие виртуальных функций или виртуальных базовых классов, вовлеченных в иерархию, и в этом случае такой код не понадобится, поскольку указатель this для базового класса уже отправлен неявным образом в конструктор базового класса.