2017-01-26 56 views
-2

所以..我寫了一些代碼,想知道複合算子的原型(即類似operator*=operator/=)。當我查看它時,我意識到它們應該返回引用。 (至少我的源這樣指出:R& operator +=(K& a, S b);。)嗯..然後我意識到,在我的代碼行可能會多一分危險比它似乎是:C++ - 如果我返回一個* = b;`會發生什麼?

// I have a really fancy Vector class I've been making. :P 
template<typename T, int N> 
inline Vector<T, N> operator*(const Vector<T, N>& vec, T scale) { 
    Vector<T, N> ret = vec; 
    return ret *= scale; 
} 

所以..我想知道如果這是無害的......或者會導致引用局部變量泄漏並導致各種未定義的行爲和普遍的破壞。 (我傾向於破壞,並且,正因爲如此,它改寫如下:P)

// I have a really fancy Vector class I've been making. :P 
template<typename T, int N> 
inline Vector<T, N> operator*(const Vector<T, N>& vec, T scale) { 
    Vector<T, N> ret = vec; 
    ret *= scale; 
    return ret; 
} 

所以..啊..一般的C++ 「有什麼關係?」問題在這裏。很高興知道肯定。 (而且我懶得去試一下測試用例,看看我的程序是否暫停並着火了:P)

編輯:修正了上面的代碼之後..我意識到它可能有助於把上述化合物運營商也在這裏。 :P

template<typename T, int N> 
inline Vector<T, N>& operator*=(Vector<T, N>& vec, T scale) { 
    for (int i = 0; i < N; i++) { 
     vec[i] *= scale; 
    } 
    return vec; 
} 

所以..與糾正代碼(雙重檢查),我使用的第一個變體仍然會導致懸掛引用或不知道是否(因爲operator*=返回類型爲參考) 。

+2

就我所見,這兩個例子都做同樣的事情:它們返回一個對局部變量的引用,該變量立即超出範圍並且不再存在。 –

+0

@JerryJeremiah當然他們不......後者肯定不會返回對局部變量的引用。前者......那是我的問題!編輯:嗯..我再次看着它,我現在看到它..忽略這一點。 :P –

+0

@CorneliaXaos函數的兩個版本的返回類型都是'Vector &',它是一個引用,並且返回'ret',這是一個局部變量。因此,您正在返回對局部變量的引用。 –

回答

5

按照慣例,像*=這樣的複合賦值運算符應該返回對它們修改的對象的引用,因爲沒有理由進行不必要的複製。也就是說,即使在你修改過的例子中,你也會得到一個「搖晃」的引用,因爲你仍然返回一個局部變量的引用,這個變量在函數返回後將被銷燬。您應該通過值而不是通過引用返回。

template <typename T, int N> 
Vector<T, N> operator*(Vector<T, N> const& vec, T scale) { 
    Vector<T, N> ret = vec; 
    return ret *= scale; 
} 

還要注意的是,你可以擺脫ret如果按值傳遞vec。如果Vector<T, N>可以被移動得比它能被複制的效率更高,這可以允許更有效的客戶端代碼。

template <typename T, int N> 
Vector<T, N> operator*(Vector<T, N> vec, T scale) { 
    return vec *= scale; 
} 
+0

拍攝..我輸入了錯誤的代碼.. XD –

+0

是的。我需要做一些類似於你提供的後一個例子(但輸入的vec應該仍然是const)。 –

+1

@CorneliaXaos:輸入不應該是'const',它是按值傳遞的,它可以根據需要複製或移動操作數。然後返回移動結果。 –

0

你有兩個選擇:

如果你定義它需要一個參數和修改類數據並返回*這不返回一個局部變量的類操作:

R& K::operator *=(S b); 

如果在類外定義運算符,則需要兩個參數,然後修改該參數並返回該參數而不返回局部變量:

R& operator *=(K& a, S b); 

從下規範實現http://en.cppreference.com/w/cpp/language/operators他們有這樣的例子:

class X 
{ 
public: 
    X& operator+=(const X& rhs)  // compound assignment (does not need to be a member, 
    {        // but often is, to modify the private members) 
    /* addition of rhs to *this takes place here */ 
    return *this; // return the result by reference 
    } 

    // friends defined inside class body are inline and are hidden from non-ADL lookup 
    friend X operator+(X lhs,  // passing lhs by value helps optimize chained a+b+c 
        const X& rhs) // otherwise, both parameters may be const references 
    { 
    lhs += rhs; // reuse compound assignment 
    return lhs; // return the result by value (uses move constructor) 
    } 
}; 
1

(雖然@ JosephThomson的下面的「答案」這個問題的答案,它沒有說出來的簡單,因爲我覺得它應該是這樣,我提供在這裏回答。)

template<typename T, int N> 
inline Vector<T, N> operator*(const Vector<T, N>& vec, T scale) { 
    Vector<T, N> ret = vec; 
    return ret *= scale; 
} 

在上述return ret *= scale;原因懸空參考誤差。原因是返回類型是Vector<T, N>,並且是而不是的引用類型。因此,即使operator*=被定義爲返回一個引用類型,當operator*返回(有效剝離引用)時會產生一個副本。

相關問題