[英]C++ - What happens if I `return a*= b;`?
所以.. 我正在寫一些代碼,想知道復合運算符的原型(即像operator*=
或operator/=
)。 當我查找它時,我意識到他們應該返回引用。 (或者至少我的消息來源是這樣表示的: R& operator +=(K& a, S 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*=
的返回類型是引用)。
按照慣例,像*=
這樣的復合賦值運算符應該返回對它們修改的對象的引用,因為沒有理由進行不必要的復制。 也就是說,即使在您修改的示例中,您也會得到一個“懸空”引用,因為您仍在返回對局部變量的引用,該變量將在函數返回后被銷毀。 您應該按值而不是按引用返回。
template <typename T, int N>
Vector<T, N> operator*(Vector<T, N> const& vec, T scale) {
Vector<T, N> ret = vec;
return ret *= scale;
}
另請注意,如果按值傳遞vec
,則可以擺脫ret
。 如果Vector<T, N>
可以比復制更有效地移動Vector<T, N>
這可能允許更有效的客戶端代碼。
template <typename T, int N>
Vector<T, N> operator*(Vector<T, N> vec, T scale) {
return vec *= scale;
}
(雖然@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*
返回時生成副本(有效地剝離引用)。
你有兩個選擇:
如果您在類中定義運算符,它需要一個參數,您修改類數據並返回 *this 而不返回局部變量:
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)
}
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.