问题
i ran into a segfault running the following program
#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;
}
When i replace vec
with a member of type int
it doesn't segfault anymore. Why?
回答1:
Your code has undefined behavior. The problem comes from the order of the initialization; for the derived class CRTPChild
, the constructor of the base class CRTPBase<CRTPChild>
is invoked firstly, after that the data member vec
of CRTPChild
get initialized. When _func
is invoked (from the constructor of the base class) vec
is not initialized at all.
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.
Changing the type to int
it's still UB. UB means anything is possible, it might lead to segfault or might not.
回答2:
When CRTPBase
constructor is called, CRTPChild
is not yet fully constructed, so calling it's member function is undefined behavior.
The way undefined behavior manifests itself depends on platform, compiler and phase of the moon.
In particular, when your member is an int, the fact that it is not yet constructed doesn't cause program to crash when you are using int - there are no invariants for int
. Vector, on the other hand, has invariants, so accessing unconstructed vector will violate them, and cause incorrect memory access.
回答3:
The base-class will be initialized (i.e. constructed) before the child class. That means when you call CRTPChild::_func
the CRTPChild
part of the object (including the vector) haven't been constructed yet. Using the vector in any way will lead to undefined behavior.
Don't access (non-static) members of child-classes in a base-class constructor.
来源:https://stackoverflow.com/questions/61000594/can-a-crtp-base-class-constructor-access-derived-data-members