5

下面的错误让我感到困惑。这是一段更复杂的代码。对我来说很奇怪,只有模板化构造函数和虚拟方法的存在才会导致错误,并且只有在复制初始化对象时才会发生错误。

有人有想法吗?谢谢。

    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;
    }
4

2 回答 2

5

您所拥有的是复制省略和制作参数副本的构造函数的令人讨厌的融合。

首先,让我们澄清一个误解:A a = c;不等于. 第一个调用复制ctor,第二个调用赋值运算符。使用此代码示例亲自查看。A a; a = c;

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

virtual void f()当您没有in时,为什么不会发生这种情况B?这是复制省略的副作用,它是一个依赖于实现的特性。拥有虚拟方法可能足以让视觉工作室决定不删除副本,但无论如何你不应该依赖它。这就是为什么强烈建议您不要对复制 ctor 产生可观察到的副作用

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

于 2013-04-04T00:56:09.560 回答
2
    A a=c; // this results in A::A(C c) template constructor instantiation.

之后是递归,因为要复制,您需要复制,您需要复制.... :)

正确使用请参考this

于 2013-04-04T01:44:52.000 回答