Методы вызова неструктурированных объектов: законно? - PullRequest
4 голосов
/ 16 апреля 2019

Если память выделена для объекта (например, через объединение), но конструктор еще не был вызван, допустимо ли вызывать один из нестатических методов объекта, предполагая, что метод не зависит от значения каких-либо переменных-членов?

Я немного исследовал и нашел некоторую информацию о «вариантах членов», но не смог найти информацию, относящуюся к этому примеру.

class D {
 public:
  D() { printf("D constructor!\n"); }
  int a = 123;
  void print () const {
    printf("Pointer: %p\n", &a);
  };
};

class C {
 public:
  C() {};
  union {
    D memory;
  };
};

int main() {
  C c;
  c.memory.print();
} 

В этом примере я вызываю print () без вызова конструктора. Намерение состоит в том, чтобы позже вызвать конструктор, но даже до вызова конструктора мы знаем, где будет находиться переменная a . Очевидно, что значение a на этом этапе неинициализировано, но print () не заботится о значении.

Кажется, что это работает должным образом при компиляции с gcc и clang для c ++ 11. Но мне интересно, не вызываю ли я здесь какое-то незаконное или неопределенное поведение.

1 Ответ

6 голосов
/ 16 апреля 2019

Я считаю, что это неопределенное поведение.Ваш вариантный член C::memory не был инициализирован, потому что конструктор C не предоставляет инициализатор [class.base.init] /9.2.Следовательно, время жизни c.memory еще не началось в точке, где вы вызываете метод print() [basic.life] / 1 .На основе [basic.life] /7.2:

Аналогично, до начала срока службы объекта, но после того, как было выделено хранилище, которое будет занимать объект или, после окончания срока службы объекта и до повторного использования или освобождения хранилища, в котором занятый объект, может использоваться любое значение, относящееся к исходному объекту, но только ограниченным образом.[…] Программа имеет неопределенное поведение, если :

  • […]
  • glvalue используется для вызова нестатической функции-членаобъект или
  • […]

выделение

Примечание: я имею в виду текущий черновик стандарта C ++ выше, однако, соответствующая формулировка в основном такая же для C ++ 11, за исключением того, что в C ++ 11 тот факт, что D имеет нетривиальную инициализацию, имеет решающее значение, поскольку то, что вы делаете, может потенциально потенциальнобыть в порядке в C ++ 11 ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...