2016-10-04 75 views
1

我試圖超載分區運算符/對於Polynomial類,但算法本身是無關緊要的。問題是,當我嘗試返回它出於某種未知的原因時,C++似乎正在破壞我的多項式。C++:如何避免從方法返回後矢量被破壞?

這是類的相關部分:

class Polynomial 
{ 
    public: 
     ......... 
     Polynomial &operator/(const double &) const; 
    private: 
     int DEGREE; 
     std::vector<double> poly_terms; // stores the polynomial coefficients 
     ......... 
} 

而且這是我不能正常工作的方法:

Polynomial &Polynomial::operator/(const double &rhs) const 
{ 
    Polynomial result(10); //create new polynomial object with a maximum degree of 10 
    double buffer; 

    for(int i = 0; i <= DEGREE; i++) 
    { 
     buffer = poly_terms[i]; //poly_terms is of type vector<double> 
     result.setCoeff(i, buffer/rhs); //this method assigns (buffer/rhs) to the i-th index of result's vector data-member. 
    } 
    return result; //return Polynomial instance 
} 

執行return子句前右,一個調試器顯示result對象的所有數據成員的值都正確設置,因爲算法應該設置它們,包括vector數據成員。所以在return返回之前,result是100%正確構建的,因此該方法的邏輯看起來很好。

但是在執行return語句之後,所有內容都不能正常運行。由於某種原因,返回的對象將其vector數據成員更改爲空vector(奇怪的是,其他所有不是對象的數據成員(如DEGREE)仍然保持原樣)。我不確定它是否是以某種方式清空的相同矢量對象,或者如果它是包含此矢量對象的多項式對象的失敗副本。

有誰知道爲什麼會發生這種情況,我該如何避免它?

UPDATE1: 我要指出,我也嘗試用new創造此法的Polynomial對象。而且我也嘗試不通過刪除&來返回參考,所以有一個像Polynomial Polynomial::operator/(const double &rhs) const這樣的標題。但是這兩個都對vector數據成員產生了類似的不良影響。

UPDATE2: 看來我能夠追查到這個問題,這要歸功於那些提到我不應該返回引用的人。問題在於,需要重載複製構造函數並重載賦值運算符以手動執行向量數據成員的副本(不確定是否需要這兩個副本),我只是實現了所有3個這些東西,現在它完美地工作) 。感謝大家幫助解決這個問題。

+3

不要返回被實例化多項式參照。請參閱:http://stackoverflow.com/questions/4421706/operator-overloading – NathanOliver

+0

您已經在堆棧中創建了'result',而您需要使用'new'在堆上創建它。 –

+1

這是未定義的行爲,您將返回臨時引用。只是回報價值和解決問題。 – 101010

回答

3

至少在Visual Studio中,這段代碼應該給你一個警告,因爲你使用了一個對被銷燬的臨時對象的引用,所以你使用了一個對你不瞭解的引用。這是未定義的行爲。

只需按值返回result即可解決問題。如果矢量很大,並且擔心按值返回的性能,則可以設置一個移動構造函數Polynomial,以便在其中移動矢量而不是複製它。

6

那麼,你返回一個局部變量的引用。任何將使用該變量的代碼都是未定義的行爲。有你的情況下,簡單的解決方案:去掉&

// Notice that the function is not returning a reference anymore 
Polynomial Polynomial::operator/(const double &rhs) const 
{ 
    Polynomial result(10); //create new polynomial object with a maximum degree of 10 
    double buffer; 

    for(int i = 0; i <= DEGREE; i++) 
    { 
     buffer = poly_terms[i]; //poly_terms is of type vector<double> 
     result.setCoeff(i, buffer/rhs); //this method assigns (buffer/rhs) to the i-th index of result's vector data-member. 
    } 
    return result; //return Polynomial 
} 

你可能會認爲它會減緩你的代碼,因爲它將變量result。這是錯誤的。您的代碼將使用複製elision。這意味着沒有複印件的形式。

即使你的編譯器是愚蠢的,不會使用複製elision,它將使用你的類的移動構造函數,它仍然比副本更快。

要了解更多有關複製省略,查看文檔頁面在這裏:Copy elision

1

我看到三個問題與您的代碼(雖然不是所有的人都造成你的煩惱):

  1. 正如其他指出,只要程序退出運算符重載函數,就返回一個對象的引用。您可以返回多項式對象

  2. 您循環索引從0到DEGREE(所以DEGREE + 1項目被修改)。我假設DEGREE是從多項式構造函數的int輸入參數定義的。我希望從0定義爲度環 - 1

  3. 我也想到了「結果」多項式對象使用DEGREE度,而不是硬編碼的10

+0

1.是的,這似乎是問題發生的關鍵因素。 2. DEGREE存儲多項式中最大指數的int值,所以矢量的大小爲(度+ 1)。因爲它是算法的一部分,所以我不好意思,因爲它是與算法無關的。 3.你絕對正確。在我的實際代碼中,10被DEGREE替換。我只是把10放在我的例子中,以便更容易閱讀。 感謝您的意見。 – programmar

+1

DEGREE的使用可能是正確的 - 一個2次多項式有3個項(0,1,2)等 –