我遇到了运行以下程序的段错误
#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
的成员时,它将不再存在段错误。为什么?
答案 0 :(得分:3)
调用CRTPBase
构造函数时,CRTPChild
尚未完全构造,因此调用其成员函数是未定义的行为。
未定义行为表现出来的方式取决于平台,编译器和月相。
特别是,当您的成员是一个int时,尚未构造它的事实并不会在您使用int时导致程序崩溃-int
没有任何不变式。另一方面,向量具有不变量,因此访问未构造的向量将违反它们,并导致错误的内存访问。
答案 1 :(得分:3)
您的代码具有未定义的行为。问题来自order of the initialization;对于派生类CRTPChild
,首先调用基类CRTPBase<CRTPChild>
的构造函数,然后初始化vec
的数据成员CRTPChild
。从基类的构造函数调用_func
时,vec
根本没有初始化。
2)然后,直接基类按从左到右的顺序初始化为 它们出现在此类的基本说明符列表中
3)然后,按以下顺序初始化非静态数据成员 类定义中的声明。
将类型更改为int
仍为UB。 UB意味着一切皆有可能,它可能导致段错误或可能不会。
答案 2 :(得分:2)
基类将在子类之前初始化(即构造)。这意味着当您调用CRTPChild::_func
时,尚未构造对象的CRTPChild
部分(包括向量)。以任何方式使用向量都会导致undefined behavior。
不要在基类构造函数中访问子类的成员(非静态)。