当使用复制构造函数并且存在虚函数时,错误“在所有控制路径上递归”

时间:2013-04-04 00:12:48

标签: c++ templates visual-c++ multiple-inheritance virtual-method

以下错误让我感到困惑。这是一段更复杂的代码。我觉得很奇怪,只有模板化构造函数和虚方法都存在错误,并且只有在复制初始化对象时才会出现错误。

有没有人有想法?感谢。

    class A
    {
      long *p;
    public:
      A():p(0)
      {
      }

      template<class T>
      A(T val):p(val)// 1
      {
      }

      operator long*()
      {
       return p;
      }
    };

    class B
    {
      virtual void f()// 2
      {
      }
    };

    class C : public A, public B
    {
    };

    void main()
    {
      C c;

main()中的下一行是

      A a=c; 

如果标记为// 1// 2的行都存在,则会触发以下错误:

warning C4717: 'C::C' : recursive on all control paths, function will cause runtime stack overflow 

但是在main()中使用以下内容时,没有错误:

      A a;
      a=c;
    }

2 个答案:

答案 0 :(得分:4)

你所拥有的是copy elision与制作参数副本的构造函数的令人讨厌的融合。

首先,让我们澄清一个误解:A a = c; 等同于A a; a = c;。第一个调用copy ctor,第二个调用赋值运算符。使用this code sample查看自己。

构造函数A::A<T>(T)可以在调用时复制T。不幸的是,如果您使用A参数(或在您的示例C中调用它,即A),参数将尝试复制自身,调用A::A<T>(T)再次,它再次复制自己,再次......直到堆栈溢出。

如果virtual void f()中没有B,为什么不会发生这种情况?这是copy elision的副作用,它是一个依赖于实现的功能。拥有虚拟方法可能已经足以让visual studio决定不删除副本,但无论如何你不应该依赖它。这就是你strongly advised not to have observable side-effects for copy ctors的原因。

如果您正在寻找解决方案,可以通过更改A::A<T>(T)来删除副本以获取参考,例如A::A<T>(T&)。更好的是,选择const T&,因为这有助于确保ctor中没有副作用(因为您无法修改T)。

答案 1 :(得分:1)

    A a=c; // this results in A::A(C c) template constructor instantiation.

之后是递归,因为要制作副本,你需要制作副本,你需要复制....:)

如需正确使用,请参阅this