考虑这段代码:
struct foo {
int a;
};
foo q() {
foo f;
f.a = 4;
return f;
}
int main() {
foo i;
i.a = 5;
q() = i;
}
没有编译器抱怨它,甚至 Clang 也是如此。为什么这个说法
q() = ...
是正确的?
不,函数的返回值当且仅当它是引用时才是左值 (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 中产生负面影响,因为它可能会阻止移动语义正常工作。
因为可以分配结构体,并且您的
q()
返回 struct foo
的副本,因此它将返回的结构体分配给提供的值。
在这种情况下,这并没有真正做任何事情,因为该结构随后超出了范围,并且您一开始就没有保留对它的引用,因此无论如何您都无法对其执行任何操作(在这个特定代码中) .
这更有意义(尽管仍然不是真正的“最佳实践”)
struct foo
{
int a;
};
foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }
int main()
{
foo i;
i.a = 5;
//sets the contents of the newly created foo
//to the contents of your i variable
(*(q())) = i;
}
一个有趣的应用:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
这里,
g() +=
修改了临时变量,这可能比使用+
创建额外的临时变量更快,因为为g()的返回值分配的堆可能已经有足够的备用容量来容纳</tag>
。
查看它在 ideone.com 上使用 GCC / C++11 运行。
现在,哪位计算新手说过一些关于优化和邪恶的话……? ;-].