C ++ CRTP инициализация - PullRequest
       39

C ++ CRTP инициализация

0 голосов
/ 09 октября 2018

я столкнулся с segfault, запустив следующую программу

#include <iostream>
#include <vector>

template <typename Derived>
struct CRTPBase {
  CRTPBase() {
    func();
  }
  void func() {
    static_cast<Derived*>(this)->_func();
  }
};
struct CRTPChild : CRTPBase<CRTPChild>{
  using CRTPBase<CRTPChild>::CRTPBase;
  void _func(){
    vec.resize(10);
    vec[0] = 2;
  }
  std::vector<int> vec;
};
int main()
{
    CRTPChild obj;
    std::cout << obj.vec[0] << std::endl;
}

Когда я заменяю vec на член типа int, он больше не переходит на segfault.Почему?

Ответы [ 3 ]

0 голосов
/ 09 октября 2018

Когда вызывается конструктор CRTPBase, CRTPChild еще не полностью создан, поэтому вызов его функции-члена является неопределенным поведением.

Способ проявления неопределенного поведения зависит от платформы, компилятора и фазы луны.

В частности, когда ваш член имеет тип int, тот факт, что он еще не создан, не имеетвызвать сбой программы при использовании int - нет инвариантов для int.Вектор, с другой стороны, имеет инварианты, поэтому доступ к неструктурированному вектору нарушит их и приведет к неправильному доступу к памяти.

0 голосов
/ 09 октября 2018

Ваш код имеет неопределенное поведение.Проблема возникает из порядка инициализации ;для производного класса CRTPChild сначала вызывается конструктор базового класса CRTPBase<CRTPChild>, после чего инициализируется элемент данных vec из CRTPChild.Когда _func вызывается (из конструктора базового класса), vec вообще не инициализируется.

2) Затем прямые базовые классы инициализируются в порядке слева направо какони появляются в списке базовых спецификаторов этого класса

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

Изменение типа на int это все еще UB .UB означает, что все возможно, это может привести к segfault или нет.

0 голосов
/ 09 октября 2018

Базовый класс будет инициализирован (т.е. создан) перед дочерним классом.Это означает, что когда вы вызываете CRTPChild::_func, часть CRTPChild объекта (включая вектор) еще не была построена.Любое использование вектора приведет к неопределенному поведению .

Не получать доступ к (нестатическим) членам дочерних классов в конструкторе базового класса.

...