Порядок списка инициализаторов в C ++ - PullRequest
1 голос
/ 14 марта 2019

Я понимаю, что для нестатических переменных-членов порядок вычисления в списке инициализатора соответствует порядку объявления в классе.

Рассмотрим пример ниже из isocpp

#include <iostream>

class Y {
   public:
      Y();
      void f();
};

Y::Y()      { std::cout << "Initializing Y\n"<<this<<"\n"; }

void Y::f() { std::cout << "Using Y\n"<<this<<"\n"; }

class X {
   public:
      X(Y& y);
};

X::X(Y& y) { y.f(); }

class Z {
   public:
      Z() throw();
   protected:
      X x_;
      Y y_;
};

Z::Z() throw() : y_(), x_(y_) {}

int main()
{
   Z z;
   return 0;
}

Поскольку ctor X требует ссылки Y, мы в идеале должны сначала инициализировать y_;это означает, что y_ должен быть объявлен до x _.

Я ожидал, что вышеупомянутая программа выдаст ошибку seg, но ниже мой o / p.Может кто-нибудь пролить свет на это.

-bash-4.1$ ./a.out
Using Y
0x7fffffffe0c1
Initializing Y
0x7fffffffe0c1

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Я ожидал, что вышеупомянутая программа выдаст ошибку сегмента, но ниже мой o / p.

Теоретически ваш код подвержен неопределенному поведению.

Пробел былвыделен для объекта, но он не был инициализирован.Такие объекты и указатели на такие объекты могут использоваться ограниченным образом, но вызов нестатической функции-члена для такого объекта является причиной неопределенного поведения.

From https://timsong -cpp.github.io/cppwp/n3337/basic.life#5:

Программа имеет неопределенное поведение, если:

(5.1) объект будет или имел тип класса снетривиальный деструктор и указатель используется в качестве операнда выражения удаления,

(5.2) указатель используется для доступа к нестатическому элементу данных или вызова нестатической функции-членаobject, или

Наиболее вероятная причина, по которой вы не видите плохого поведения, состоит в том, что Y не имеет переменных-членов.Если вы добавите переменную-член в Y и будете использовать ее в Y:f(), вы, скорее всего, заметите проблему с большей готовностью.

0 голосов
/ 14 марта 2019
class Z {
   public:
      Z() throw();
   protected:
      X x_;
      Y y_;
};

Z::Z() throw() : y_(), x_(y_) {}

В Z вы объявляете x_ до y_. Следовательно, x создается до y_ независимо от порядка ваших инициализаторов.

И инициализация x_(y_) до построения y_ приводит к неопределенному поведению.


Я ожидал, что вышеуказанная программа выдаст ошибку seg

Неопределенное поведение не определено. Вы не должны ожидать ничего особенного.

...