C++ CRTP初始化

C++ CRTP initialization

i 运行进入段错误运行下面的程序

#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;
}

当我用 int 类型的成员替换 vec 时,它不再出现段错误。为什么?

base-class 将在子 class 之前初始化(即构造)。这意味着当您调用 CRTPChild::_func 时,对象的 CRTPChild 部分(包括向量)尚未构建。以任何方式使用向量将导致 undefined behavior.

不要在 base-class 构造函数中访问 c​​hild-classes 的(非静态)成员。

调用CRTPBase构造函数时,CRTPChild还没有完全构造好,所以调用它的成员函数是未定义行为。

未定义行为的表现方式取决于平台、编译器和月相。

特别是,当您的成员是一个 int 时,它尚未构造的事实不会导致程序在您使用 int 时崩溃 - int 没有不变量。另一方面,Vector 具有不变量,因此访问未构造的 vector 将违反它们,并导致不正确的内存访问。

您的代码有未定义的行为。问题来自order of the initialization;对于派生classCRTPChild,首先调用基classCRTPBase<CRTPChild>的构造函数,然后CRTPChild的数据成员vec得到初始化。当 _func 被调用时(从基础 class 的构造函数) vec 根本没有被初始化。

2) Then, direct base classes are initialized in left-to-right order as they appear in this class's base-specifier list

3) Then, non-static data members are initialized in order of declaration in the class definition.

将类型更改为 int 它仍然是 UB。 UB 意味着一切皆有可能,它可能会导致段错误,也可能不会。