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

Joh*_*ohn 71 c++ return-value lvalue

考虑以下代码:

struct foo
{
  int a;
};

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

int main()
{
  foo i;
  i.a = 5;
  q() = i;
}
Run Code Online (Sandbox Code Playgroud)

没有编译器抱怨它,甚至Clang.为什么q() = ...线路正确?

CB *_*ley 66

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

  • 举一个具体的例子,考虑`std :: cout <<"Hello,world"<< std :: endl`.第一个`operator <<()`返回一个左值,你可以在其上调用第二个`operator <<()`.因此,这种在返回值上调用方法的做法比许多人想象的更为常见. (17认同)
  • @MSalters是的,但是在`cout`的情况下它_actually_返回一个左值(它返回自己并通过引用,`*this`),而不是值的东西.所以它有点不同. (11认同)
  • @MSalters:ostream :: operator <<,like operator = both返回引用,也就是L值. (5认同)
  • 这让我想起了"C++的设计和演变"的引用:_这是多年来成为C++设计经验法则的概念的起源:用户定义和内置类型应该表现为与语言规则相同,并从语言及其相关工具获得相同程度的支持.当理想被制定为内置类型时,获得了迄今为止最好的支持,但是C++已超出目标,因此与用户定义的类型相比,内置类型现在获得的支持略逊一筹._ (4认同)
  • @MSalters在`std :: cout <<"duh"<< std :: endl`中,`operator <<`都返回非const引用(它们是lvalues),并且因为运算符都需要非const引用他们的第一个参数,原始的`std :: ostream`对象不能是右值.在其他示例中(我认为这是问题的动机),非const函数被临时调用. (4认同)

Cha*_*had 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 它与此之间有什么区别:`int blah(){int f = 4; 返回f; } int main(){int a = 99; blah()= a; 结构是什么神奇的东西?因为该代码不能编译. (5认同)
  • Int没有成员函数,因此它们也没有`int :: operator =(int)`.这是关于结构的"神奇"一点:它们有默认方法. (2认同)
  • @bruno:`s/无/任何/` (2认同)

Ton*_*roy 7

一个有趣的应用:

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

...

f(g() += "</tag>");
Run Code Online (Sandbox Code Playgroud)

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

通过GCC/C++ 11查看它在ideone.com上的运行情况.

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