C++11 元编程中的堆栈溢出

C++11 元编程中的堆栈溢出,c++11,inheritance,stack-overflow,copy-constructor,template-meta-programming,C++11,Inheritance,Stack Overflow,Copy Constructor,Template Meta Programming,我正在读《经典C++高级元编程》一书!在第16页,作者提供了一个例子: struct base { base() {} template <typename T> base(T x) {} }; struct derived : base { derived() {} derived(const derived& that) : base(that) {} }; void main() { derived d1;

我正在读《经典C++高级元编程》一书!在第16页,作者提供了一个例子:

struct base
{
    base() {}
    template <typename T>
    base(T x) {}
};
struct derived : base
{
    derived() {}
    derived(const derived& that)
        : base(that) {}
};
void main()
{
    derived d1;
    derived d2 = d1; //stack overflow!! why?! 
}
struct base
{
base(){}
样板
碱基(tx){}
};
派生结构:基
{
派生(){}
派生(const派生&that)
:base(that){}
};
void main()
{
衍生d1;
派生d2=d1;//堆栈溢出!!为什么?!
}
作者说: “赋值D2= D1导致堆栈溢出。隐式复制构造函数必须调用基类的复制构造函数,因此可以通过它的12.8(C++标准)来调用。 永远不要调用通用构造函数。如果编译器为派生生成了一个副本构造函数,它将调用基副本构造函数(隐式)。不幸的是,为派生生成了一个副本构造函数,它包含一个显式函数调用,即base(that)。因此,按照通常的重载解析规则,它将通用构造函数与T=derived匹配。由于此函数按值获取x,因此需要执行该函数的副本,因此调用是递归的。”

我真的不明白!有人能解释一下吗


非常感谢!:)

主要问题在于:

base(T x) {}
base的构造函数将x(表示d1)作为值,这会导致临时复制x。复制x将导致再次调用派生的原始复制构造函数,即:

derived(const derived& that)
    : base(that) {}

此构造函数本身将再次调用第一个构造函数(base(tx)),以此类推,因为递归构造函数调用会导致堆栈溢出。

主要问题在于:

base(T x) {}
base的构造函数将x(表示d1)作为值,这会导致临时复制x。复制x将导致再次调用派生的原始复制构造函数,即:

derived(const derived& that)
    : base(that) {}

此构造函数本身将再次调用第一个构造函数(base(tx)),以此类推,这样您就会得到由递归构造函数调用引起的堆栈溢出。

我在代码中设置了断点,这就是实际发生的情况!当它到达时:导出d2=d1;然后转到派生(const-derived&that):base(that){},然后显示堆栈溢出消息!虽然我在基(tx){}处放置了断点,但它从未在基(tx){}处停止。我不知道为什么?!我最好的猜测是,您的IDE此时正在识别堆栈溢出,并且正在中断执行以防止填满内存。在调试代码时,编译器应该一步一步地运行代码!当它到达:base(that)时,您按step in,基类上有一个断点,您希望代码在基类构造函数处停止!这永远不会发生!一个递归应该正好填满内存!我调试代码时看不到递归。顺便说一句,我正在使用VS2015调试代码。正如我已经说过的,IDE或者更可能是它背后的调试器会重新对递归校准进行控制,并阻止您强制执行此操作。一个好的调试器应该能够防止类似的事情,即使是在调试问题上,因为这是一个基本问题。我在代码中设置了断点,这就是实际发生的情况!当它到达时:导出d2=d1;然后转到派生(const-derived&that):base(that){},然后显示堆栈溢出消息!虽然我在基(tx){}处放置了断点,但它从未在基(tx){}处停止。我不知道为什么?!我最好的猜测是,您的IDE此时正在识别堆栈溢出,并且正在中断执行以防止填满内存。在调试代码时,编译器应该一步一步地运行代码!当它到达:base(that)时,您按step in,基类上有一个断点,您希望代码在基类构造函数处停止!这永远不会发生!一个递归应该正好填满内存!我调试代码时看不到递归。顺便说一句,我正在使用VS2015调试代码。正如我已经说过的,IDE或者更可能是它背后的调试器会重新对递归校准进行控制,并阻止您强制执行此操作。一个好的调试器应该能够防止这样的事情,即使是调试问题,因为这是一个基本问题。