考虑这段代码:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
没有编译器抱怨它,即使是 Clang。为什么q() = ...
线是正确的?
考虑这段代码:
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)
这样做的原因是您可以const
在类类型的 r 值上调用成员函数(甚至是非成员函数),并且赋值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运行。
现在,哪个计算新手说过优化和邪恶……?;-]。
除了其他好的答案之外,我想指出的是,它std::tie
在这种机制之上可以从另一个函数中解包数据。见这里。所以它本身不容易出错,请记住它可能是一种有用的设计模式