lao*_*uca 2 c++ crtp stack-corruption
当在MSVC 2013,x64 Debug config上运行以下代码时,它会在退出main()函数时显示一个带有此着名错误消息的消息框
"Run-Time Check Failure #2 - Stack around the variable 'tmp' was corrupted.".
Run Code Online (Sandbox Code Playgroud)
我无法回答的问题是:为什么?
请注意,在Release配置上运行时不会出现任何错误消息.(为什么?)
免责声明:这只是一个示例代码,这意味着我试图在其他类(一个基础和几个派生)上使用相同的设计,使用更多的方法和模板参数,并且使用比基本的int*更复杂的数据类型.
#include <iostream>
template <class T>
class base {
public:
base() {
static_cast<T*>(this)->setData();
}
~base() {
static_cast<T*>(this)->destroyData();
}
void print() {
static_cast<T*>(this)->print_int();
}
};
Run Code Online (Sandbox Code Playgroud)
class derived : public base<derived> {
public:
void setData() {
x = new int();
}
void destroyData() {
delete x;
x = nullptr;
}
void print_int() {
std::cout << "x = " << *x << std::endl;
}
private:
derived() {}
derived(const derived& other) {}
inline derived& operator= (derived copy) {}
int *x;
};
Run Code Online (Sandbox Code Playgroud)
int main() {
base<derived> tmp;
tmp.print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑: @Yakk如果我理解正确,你建议解决这个代码:
#include <iostream>
template <class T>
class mix_in : public T
{
public:
mix_in() { (this)->setData(); }
~mix_in() { (this)->destroyData(); }
void print() { (this)->print_int(); }
};
Run Code Online (Sandbox Code Playgroud)
class foo
{
public:
void setData()
{
x = new int();
}
void destroyData()
{
delete x;
x = nullptr;
}
void print_int()
{
std::cout << "x = " << *x << std::endl;
}
foo() {}
private:
int *x;
};
Run Code Online (Sandbox Code Playgroud)
int main()
{
mix_in<foo> tmp;
tmp.print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它工作得很好,谢谢.我可能会使用这种模式,因为似乎没有解决方案将CRTP用于我正在尝试的事情.
但我仍然想了解堆栈损坏发生的原因.尽管围绕使用的所有讨论都使用CRTP进行所有事情,但我想非常清楚地理解它为什么会发生.
再次感谢你.
至于您的代码如下所示main():
int main() {
base<derived> tmp;
tmp.print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
base<derived> tmp;你想要的是这种模式的错误用法derived tmp;.
CRTP的要点是派生类被注入到基类中,并为在编译时解析的某些功能提供实现.
基类本质上是预期的,仅通过继承进行实例化.因此,您应该确保在继承上下文之外不要有任何实例化.
为了避免被这种误解困住的实现用户,make base的构造函数受到保护:
template <class T>
class base {
public:
~base() {
static_cast<T*>(this)->destroyData();
}
// ...
protected:
T* thisPtr;
base() : thisPtr(static_cast<T*>(this)) {
}
};
Run Code Online (Sandbox Code Playgroud)
注意:基类不应该调用依赖于derived基类构造函数中的完全初始化类方法的任何方法,正如您在sample(static_cast<T*>(this)->setData();)中所示!
您可以存储该引用以T*供以后使用,如上面的示例所示.
class derived : public base<derived> {
public:
derived() {
setData();
}
void destroyData() {
delete x;
x = nullptr;
}
void print_int() {
std::cout << "x = " << *x << std::endl;
}
private: // ????
derived(const derived& other) {}
inline derived& operator= (derived copy) {}
int *x;
};
Run Code Online (Sandbox Code Playgroud)
还有点不清楚,为什么你要为你的班级隐藏复制构造函数和赋值运算符?