C++:返回值是L值吗?

问题描述 投票:0回答:4

考虑这段代码:

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++ return-value lvalue value-categories
4个回答
77
投票

不,函数的返回值当且仅当它是引用时才是左值 (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 中产生负面影响,因为它可能会阻止移动语义正常工作。


8
投票

因为可以分配结构体,并且您的

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;
}

7
投票

一个有趣的应用:

void f(const std::string& x);
std::string g() { return "<tag>"; }

...

f(g() += "</tag>");

这里,

g() +=
修改了临时变量,这可能比使用
+
创建额外的临时变量更快,因为为g()的返回值分配的堆可能已经有足够的备用容量来容纳
</tag>

查看它在 ideone.com 上使用 GCC / C++11 运行

现在,哪位计算新手说过一些关于优化和邪恶的话……? ;-].


0
投票
除了其他好的答案之外,我想指出

std::tie

 在此机制之上工作,用于从另一个函数解包数据。 
看这里。所以它本身不容易出错,只要记住它可能是一个有用的设计模式

© www.soinside.com 2019 - 2024. All rights reserved.