4

以下錯誤令我困惑。這是一個非常複雜的代碼片段。我覺得奇怪的是,只有模板化的構造函數和虛擬方法的存在纔會導致錯誤,並且僅在複製初始化對象時纔會導致錯誤。使用複製構造函數並存在虛函數時出現「在所有控制路徑上遞歸」的錯誤

有沒有人有想法?謝謝。

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

你有什麼是一個討厭的合流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),它再次自我複製,直到堆棧溢出。

爲什麼不在B中沒有virtual void f()?這是複製elision的副作用,這是一個與實現相關的功能。有虛擬方法可能足以讓視覺工作室決定不復制副本,但無論如何你都不應該依賴它。這就是爲什麼你是strongly advised not to have observable side-effects for copy ctors

爲防萬一您正在尋找解決方案,您可以通過更改A::A<T>(T)以刪除副本以供參考,如A::A<T>(T&)。更好的是,採取const T&,因爲這有助於確保ctor中沒有副作用(因爲您無法修改T)。

+0

感謝您的完整性,的確我應該使用參考。 – user883041 2013-04-04 02:06:03

+1

從技術上講,它不是*拷貝構造函數*,而是一個*轉換構造函數*。 A * copy-constructor *接受與源相同類型的對象,而* conversion-constructor *接受不同類型的對象。模板構造函數不能是*拷貝構造函數*。 – 2013-04-04 03:53:18

+0

@DavidRodríguez-dribeas謝謝。更確切地說,只有該模板構造函數的特殊性(其中'T'是'A')是複製構造函數。 – congusbongus 2013-04-04 04:02:58

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

之後,它是遞歸的,因爲做一個副本,你需要做一個副本,你需要做一個副本.... :)

產品的正確使用是指this