77

考虑这段代码:

struct foo
{
  int a;
};

foo q() { foo f; f.a =4; return f;}

int main()
{
  foo i;
  i.a = 5;
  q() = i;
}

没有编译器抱怨它,即使是 Clang。为什么q() = ...线是正确的?

4

4 回答 4

70

不,一个函数的返回值是一个左值当且仅当它是一个引用(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 中可能会产生负面影响,它会阻止移动语义按应有的方式工作。

于 2011-05-24T14:26:20.557 回答
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;
}
于 2011-05-24T14:24:43.820 回答
7

一个有趣的应用:

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

...

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

在这里,g() +=修改临时,这可能比创建额外的临时更快,+因为分配给 g() 的返回值的堆可能已经有足够的空闲容量来容纳</tag>.

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

现在,哪个计算新手说过优化和邪恶……?;-]。

于 2011-05-25T04:12:28.453 回答
0

除了其他好的答案之外,我想指出的是,它std::tie在这种机制之上可以从另一个函数中解包数据。见这里。所以它本身不容易出错,请记住它可能是一种有用的设计模式

于 2021-11-27T19:45:37.880 回答