2015-12-16 35 views
1

我搜索了四周,似乎無法找到我的問題的答案。我在做一個項目,我必須重新定義一些運營商(+-*等)爲載體和多項式之間的操作。據我所知,這些運營商都應該返回對象的副本,以便不直接修改他們,如果我們簡單地調用運營商(IE的vect1+vect2;代替vect1 += vect2;),而不是把結果放置在任何地方。在方法中返回靜態變量是一個壞主意嗎?

現在,我已經看到了各地,使用靜態變量是一種不好的做法,但我怎樣才能避免這樣做,當一個方法需要返回結果的副本,而不是修改對象的?

問題herehere並沒有真正的幫助,因爲它們沒有解決我的特殊問題。

這裏是我的意思的例子:

template <class elem> 
Vect_variable<elem>& Vect_variable<elem>::operator+(const Vect_variable& operand) 
{ 
    if (taille >= operand.taille) 
     { 
     static Vect_variable<elem> temp_v; 
     temp_v = *this; 
     for (std::size_t i = 0; i<operand.taille; i++) 
      { 
      temp_v[i] += operand.vecteur[i]; 
      } 
     return temp_v; 
     } 
    else 
     { 
     static Vect_variable<elem> temp_v; 
     temp_v = operand; 
     for(std::size_t i = 0; i<taille; i++) 
      { 
      temp_v[i] += vecteur[i]; 
      } 
     return temp_v; 
     } 
} 

在這種情況下,你可以看到,我所使用的臨時變量創建靜態Vect_variable。有沒有辦法做到這一點,否則?

+3

簡單的回答:停止返回參考。 _「據我所知,這些操作員應該返回對象的副本」_確切地說,爲什麼你要返回一個參考?這不是一個對象的副本。如果你停止不正確地返回一個引用,那麼你不需要使用'static'。 –

+0

@JonathanWakely是的,不幸的是,我正在從我繼承的類中定義一個純虛方法,這就是爲什麼我必須返回引用。 – DefinitelyNotMe

+1

然後,基類破碎,愚蠢。你需要檢查預期的行爲,也許它應該修改'* this'。在其他情況下返回參考是沒有意義的,它應該提及什麼?它不能是一個靜態變量,因爲它更加破碎。 –

回答

4

是。不要使變量static。這樣每次調用函數都會得到自己新的新變量,然後返回。

此外,它的自動(堆棧上),而不是靜態的,你可以聲明變量,一氣呵成初始化。

...我沒有注意到你正在向矢量返回參考。不要這樣做。按價值歸還。

template <class elem> 
Vect_variable<elem> Vect_variable<elem>::operator+(const Vect_variable& operand) 
{ 
    if (taille >= operand.taille) 
     { 
     Vect_variable<elem> temp_v = *this; 
     for (std::size_t i = 0; i<operand.taille; i++) 
      { 
      temp_v[i] += operand.vecteur[i]; 
      } 
     return temp_v; 
     } 
    else 
     { 
     Vect_variable<elem> temp_v = operand; 
     for(std::size_t i = 0; i<taille; i++) 
      { 
      temp_v[i] += vecteur[i]; 
      } 
     return temp_v; 
     } 
} 

接下來要做的,就是要注意,你正在做幾乎同樣的事情在兩個分支。這取決於哪一個taille更短。因此,使用一對指針:

{ 
    decltype(this) one, two; 
    if (taille >= operand.taille) 
     { 
     one = this; 
     two = &operand; 
     } 
    else 
     { 
     one = &operand; 
     two = this; 
    } 

    Vect_variable<elem> temp_v = *one; 
    for (std::size_t i = 0; i<two->taille; i++) 
     { 
     temp_v[i] += two->vecteur[i]; 
     } 
    return temp_v; 
} 

最後的評論是,它通常是很好的做法寫operator +=第一,然後寫operator +與簽名非成員二元函數:

TYPE operator +(TYPE lhs, const TYPE& rhs) 
{ 
    lhs += rhs; 
    return lhs; 
} 

請注意,lhs取值(因此您已擁有自己的副本)。非成員函數的優點是,如果您有任何轉換函數到TYPE,它們將在左側和右側對稱操作。

+0

它不起作用,因爲它說它不能返回一個對已經超出範圍的對象的引用。也許改變返回類型?而且,同時聲明和初始化沒有爲我工作(一些隨機數字出現在這裏和那裏,而不是它爲我修復) 編輯 - 好吧我會改變:)謝謝 – DefinitelyNotMe

+0

順便說一句,你有任何想法爲什麼聲明和定義在同一行會產生意想不到的結果? – DefinitelyNotMe

+3

如果你有一個靜態變量,那麼在同一行上聲明和初始化會產生非常令人驚訝的效果。 *第一次*你調用函數,變量將被初始化;第二次和後續呼叫將保留先前呼叫的值。只是不要那樣做! –

2

魯棒和簡單的方法是通過值返回一個(非靜態)局部變量。在某些情況下,這也是有效的方法。

如果您關心的是效率問題,那麼您希望爲兩個輸入之一是右值的情況提供備用執行路徑。在這種情況下,你根本不需要局部變量。相反,您希望通過右值引用接受輸入,對其進行修改並通過右值引用返回。

爲了避免過多的重複代碼,你可能想定義operator+=,把真正的工作在方法和具有operator+代表工作的各個版本operator+=

有些情況下,返回static情況可變參考比以上所有更有效。但是這種情況並不多,而且它們充滿了足夠的危險,所以你不應該做出這樣的選擇。

看到您在先前的回答中所做的評論:通過引用返回static可以避免從虛擬函數的覆蓋返回多態的大問題。但它的確是以創造自己的問題爲代價的。舉一個微不足道的例子,考慮使用你的+來計算A+(B+C)。不要問爲什麼他們把那些不合適()。只是意識到他們無法知道他們不應該。因此,您的運營商將B複製到靜態並將C添加到該靜態,然後它將A複製到相同的靜態並將靜態添加到該靜態並返回2A。雖然這個例子很有意思,但它只是+可能做的很多事情之一,如果它返回一個對靜態的引用,那麼它會發生可怕的錯誤。

+0

我實際上是以^^'的方式完成它的。 My + =使用my +中的代碼。 – DefinitelyNotMe

+1

如果你不關心效率,那麼+ =委託給+可以使代碼更簡單。在很多情況下,效率並不重要。也許在一些不太明顯的情況下,效率差異是相反的。但作爲一個普遍的習慣,+ +委派給+ =更好,因爲當效率差異很大時,這是更有效的方法。 – JSF

+0

這比我的回答更好地描述了設計問題。 –

相關問題