C++-如果我`return a*=b;`会发生什么

C++ - What happens if I `return a*= b;`?

本文关键字:什么 如果 return C++-      更新时间:2023-10-16

所以。。我正在写一些代码,想知道复合运算符的原型(例如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。如果CCD_ 8可以被更有效地移动而不是被复制,则这可以允许更有效的客户端代码。

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)
}
};
相关文章: