[英]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.