Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ c++;CRTP堆栈损坏_C++_Crtp_Stack Corruption - Fatal编程技术网

C++ c++;CRTP堆栈损坏

C++ c++;CRTP堆栈损坏,c++,crtp,stack-corruption,C++,Crtp,Stack Corruption,在MSVC 2013 x64 Debug config上运行以下代码时,退出main()函数时会显示一个消息框,其中包含此著名的错误消息 "Run-Time Check Failure #2 - Stack around the variable 'tmp' was corrupted.". 我无法回答的问题是:为什么 请注意,在Release config上运行时不会出现错误消息。(为什么?) 免责声明:这只是一个示例代码,这意味着我正试图在其他类(一个基本类和几个派生类)上使用相同的设计

在MSVC 2013 x64 Debug config上运行以下代码时,退出main()函数时会显示一个消息框,其中包含此著名的错误消息

"Run-Time Check Failure #2 - Stack around the variable 'tmp' was corrupted.". 
我无法回答的问题是:为什么

请注意,在Release config上运行时不会出现错误消息。(为什么?)

免责声明:这只是一个示例代码,这意味着我正试图在其他类(一个基本类和几个派生类)上使用相同的设计,这些类具有更多的方法和模板参数,并且具有比基本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();
    }
};
#包括
模板
阶级基础{
公众:
base(){
静态_cast(this)->setData();
}
~base(){
静态_cast(this)->销毁数据();
}
作废打印(){
static_cast(this)->print_int();
}
};

派生类:公共基{
公众:
void setData(){
x=新的int();
}
void数据(){
删除x;
x=零PTR;
}
无效打印_int(){
std::cout print_int();}
};

class-foo
{
公众:
void setData()
{
x=新的int();
}
void数据()
{
删除x;
x=零PTR;
}
无效打印_int()
{

std::cout
tmp
是一个
base
,而不是
派生的
。CRTP的要点是基类“知道”对象的实际类型,因为它是作为模板参数传递的,但是如果手动创建
,则基类函数会认为该对象是
派生的
,但它不是-它只是一个
。因此会发生奇怪的事情(未定义的行为)。(如另一个答案中所述,您也在打印某些内容,但没有设置它…)


至于您的第二个问题,MSVC生成的用于检测此类程序员错误的检查似乎在发布模式下被关闭,可能是出于性能原因。

至于
main()
中显示的代码:

注意:基类不应该从基类构造函数中调用依赖于完全初始化的
派生的
类方法的任何方法,正如您的示例所示(
static_cast(this)->setData();

您可以存储对
T*
的引用,以供以后使用,如上面的示例所示


派生类:公共基{
公众:
派生的(){
setData();
}
void数据(){
删除x;
x=零PTR;
}
无效打印_int(){
std::cout
模板类混合在:public T{
公众:
base(){(this)->setData();}
~base(){(this)->destroyData();}
void print(){(this)->print_int();}
};
derived
重命名为
foo
。不要继承
foo
中的
mix\u或
base

base
交换为
main
中的
mix\u

CRTP并不是所有问题的解决方案。

你在评论中说

派生类永远不会被实例化,其构造函数永远不会被调用

其他人已经指出了未构造对象的未定义用途。具体地说,考虑<代码> int *x/c> >是<代码>派生的/<代码>成员,并且使用顺序生成调用:<代码>派生::SETYDATA()/<代码>,<代码>派生::Print()/代码>,并在退出<代码>派生::

,不存在的对象的所有成员函数,指从未为其分配过空格1的成员

但我认为你所追求的是完全合法的。分解代码是模板和继承的全部要点,也就是说,通过抽象出样板文件,使重要代码更容易识别,更不用说理解,使以后的重构更容易进行

因此:

模板
struct preconstruction\u access\u subset{};//通常为空
模板
结构基:S{
base(){S::setData();}
~base(){S::destroyData();}
void print(){S::print_int();}
};
//……以后。。。
#包括
结构派生;
模板结构预构造访问子集{
//“base”中的所有结构器都需要
int*x;
void setData(){x=new int;}
void destroyData(){delete x;}

无效打印_int(){std::cout除了下面显示的问题之外,在
派生的
的构造函数中将
x
设置为jibberish的语言是自由的吗?在
派生的
的构造函数运行之前进行
静态转换是否合法?@jthill'这个问题似乎离题了…'不,这太简单了!我标记了你的评论(和结束提议)没有建设性!@jthill easy,easy。你不知道我花了多少天试图理解为什么会发生这种问题,我读了多少帖子/论坛。就像πάντα一样ῥεῖ 我很尊重stackoverflow和在这里做出贡献的人。我只在我真的没有其他选择的时候才在这里问问题(我周围没有人知道答案或者我在网络搜索中找不到匹配的答案)@Yakk,通过像我所做的那样实例化基类,派生类的构造函数将不会被调用。我只是在调试时才意识到这一点。这就是为什么我在基类的构造函数上调用setData方法的原因。这是我无数次尝试使此代码正常工作的一部分。到目前为止,我失败了。@πνταῥεῖ & OP:看看这个和到目前为止的答案,我发现它不是看起来的那样,但让我指出我评论中的最后一个词:“显示”。如果不打赌这篇文章这次会有所不同,就不可能把它和几十篇完全相同的浪费时间的文章区分开来,我想经过深思熟虑,你会同意这篇文章目前的形式
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;
};
int main() {
    base<derived> tmp;

    tmp.print();

    return 0;
}
#include <iostream>

template <class T>
class mix_in : public T
{
public:
    mix_in() { (this)->setData(); }
    ~mix_in() { (this)->destroyData(); }
    void print() { (this)->print_int(); }
};
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;
};
int main()
{
    mix_in<foo> tmp;

    tmp.print();

    return 0;
}
int main() {
    base<derived> tmp;

    tmp.print();

    return 0;
}
template <class T>
class base {
public:
    ~base() {
        static_cast<T*>(this)->destroyData();
    }

// ...
protected:
    T* thisPtr;
    base() : thisPtr(static_cast<T*>(this)) {
    }
};
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;
};
template <class T> class mix_in:public T {
  public:
    base() { (this)->setData(); }
    ~base() { (this)->destroyData(); }
    void print() { (this)->print_int(); }
};
template < class T >
struct preconstruction_access_subset {};  // often left empty

template < class T, class S = preconstruction_access_subset<T> >
struct base : S {
        base() { S::setData(); }
       ~base() { S::destroyData(); }
        void print() { S::print_int(); }
};

// ... later ...

#include <iostream>

struct derived;
template<> struct preconstruction_access_subset<derived> {
        // everything structors in `base<derived>` need
        int *x;
        void setData()     { x = new int; }
        void destroyData() { delete x; }
        void print_int()   { std::cout << x << '\n'; }
};
struct derived : base<derived> {
        // everything no structors in any base class need to access
};

int main() {
        base<derived> tmp;
        tmp.print();
}