为什么我可以分配一个返回值的函数的结果?它是左值吗?
考虑一下这段代码:
struct foo {
int a;
};
foo q() {
foo f;
f.a = 4;
return f;
}
int main() {
foo i;
i.a = 5;
q() = i;
}
没有编译器抱怨它,甚至 Clang 也是如此。为什么 q() = ...
语句是正确的?
Consider this code:
struct foo {
int a;
};
foo q() {
foo f;
f.a = 4;
return f;
}
int main() {
foo i;
i.a = 5;
q() = i;
}
No compiler complains about it, even Clang. Why is the statement q() = ...
correct?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不,函数的返回值当且仅当它是引用时才是左值 (C++03)。 (5.2.2 [expr.call] / 10)
如果返回的类型是基本类型,那么这将是一个编译错误。 (5.17 [expr.ass] / 1)
这样做的原因是你可以在类类型的 r 值上调用成员函数(甚至是非 const 成员函数)以及赋值
foo
是一个实现定义的成员函数:foo& foo::operator=(const foo&)
。第 5 条中对运算符的限制仅适用于内置运算符,(5 [expr] / 3),如果重载决策为运算符选择重载函数调用,则适用该函数调用的限制反而。这就是为什么有时建议将类类型的对象作为
const
对象返回(例如const foo q();
),但这可能会对 C+ 产生负面影响+0x,它可以阻止移动语义正常工作。No, the return value of a function is an l-value if and only if it is a reference (C++03). (5.2.2 [expr.call] / 10)
If the type returned were a basic type then this would be a compile error. (5.17 [expr.ass] / 1)
The reason that this works is that you are allowed to call member functions (even non-
const
member functions) on r-values of class type and the assignment offoo
is an implementation defined member function:foo& foo::operator=(const foo&)
. The restrictions for operators in clause 5 only apply to built-in operators, (5 [expr] / 3), if overload resolution selects an overloaded function call for an operator then the restrictions for that function call apply instead.This is why it is sometimes recommended to return objects of class type as
const
objects (e.g.const foo q();
), however this can have a negative impact in C++0x where it can inhibit move semantics from working as they should.因为可以分配结构体,并且您的 q() 返回一个 struct foo 的副本,因此它将返回的结构体分配给提供的值。
在这种情况下,这并没有真正做任何事情,因为该结构随后超出了范围,并且您一开始就没有保留对它的引用,因此无论如何您都无法对它执行任何操作(在这个特定代码中)。
这更有意义(尽管仍然不是真正的“最佳实践”)
Because structs can be assigned to, and your
q()
returns a copy ofstruct foo
so its assigning the returned struct to the value provided.This doesn't really do anything in this case thought because the struct falls out of scope afterwards and you don't keep a reference to it in the first place so you couldn't do anything with it anyway (in this specific code).
This makes more sense (though still not really a "best practice")
一个有趣的应用:
这里,
g() +=
修改临时文件,这可能比使用+
创建附加临时文件更快,因为为 g() 分配了堆的返回值可能已经有足够的空闲容量来容纳。
查看它在 ideone.com 上使用 GCC / C++11 运行。
现在,哪个计算新手说了一些关于优化和邪恶的事情……? ;-]。
One interesting application of this:
Here,
g() +=
modifies the temporary, which may be faster that creating an additional temporary with+
because the heap allocated for g()'s return value may already have enough spare capacity to accommodate</tag>
.See it run at ideone.com with GCC / C++11.
Now, which computing novice said something about optimisations and evil...? ;-].
除了其他好的答案之外,我想指出 std::tie 在此机制之上工作,用于从另一个函数解包数据。 请参见此处。所以它本身不容易出错,只需记住它可能是一种有用的设计模式
On top of other good answers, I'd like to point out that
std::tie
works on top of this mechanism for unpacking data from another function. See here. So it's not error-prone per se, just keep in mind that it could be a useful design pattern