c++:返回值是l值吗?

时间:2020-11-27 18:48:17

Consider this code:

考虑这段代码:

struct foo
{
  int a;
};

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

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

No compiler complains about it, even Clang. Why q() = ... line is correct?

没有编译器会抱怨它,甚至是叮当声。为什么问()=…线是正确的?

3 个解决方案

#1


62  

No, the return value of a function is an l-value if and only if it is a reference (C++03). (5.2.2 [expr.call] / 10)

不,函数的返回值是l值,当且仅当它是引用时(c++ 03)。(5.2.2[expr。调用)/ 10)

If the type returned were a basic type then this would be a compile error. (5.17 [expr.ass] / 1)

如果返回的类型是基本类型,那么这将是一个编译错误。(5.17[expr。屁股]/ 1)

The reason that this works is that you are allowed to call member functions (even non-const member functions) on r-values of class type and the assignment of foo is an implementation defined member function: foo& foo::operator=(const foo&). The restrictions for operators in clause 5 only apply to built-in operators, (5 [expr] / 3), if overload resolution selects an overloaded function call for an operator then the restrictions for that function call apply instead.

这样做的原因是允许您对类类型的r值调用成员函数(甚至非const成员函数),而foo的赋值是一个实现定义的成员函数:foo&foo:operator=(const foo&)。第5条中对操作符的限制仅适用于内置操作符(5 [expr] / 3),如果重载解析为一个操作符选择了一个重载函数调用,那么该函数调用的限制将取而代之。

This is why it is sometimes recommended to return objects of class type as const objects (e.g. const foo q();), however this can have a negative impact in C++0x where it can inhibit move semantics from working as they should.

这就是为什么有时建议将类类型的对象返回为const对象(例如const foo q();),但是这可能会对c++ 0x产生负面影响,在c++ 0x中,这可能会抑制移动语义的正常工作。

#2


8  

Because structs can be assigned to, and your q() returns a copy of struct foo so its assigning the returned struct to the value provided.

因为可以为struct赋值,而q()返回struct foo的副本,因此它将返回的struct赋值给所提供的值。

This doesn't really do anything in this case thought because the struct falls out of scope afterwards and you don't keep a reference to it in the first place so you couldn't do anything with it anyway (in this specific code).

在这种情况下,它不会做任何事情,因为结构体之后会超出范围,而且你不会在一开始就对它进行引用,所以无论如何你都不能对它做任何事情(在这个特定的代码中)。

This makes more sense (though still not really a "best practice")

这更有意义(尽管还不是真正的“最佳实践”)

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

#3


5  

One interesting application of this:

一个有趣的应用是:

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

...

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

Here, g() += modifies the temporary, which may be faster that creating an additional temporary with + because the heap allocated for g()'s return value may already have enough spare capacity to accommodate </tag>.

在这里,g() +=修改临时的,这可能更快地创建一个附加的临时与+,因为为g()的返回值分配的堆可能已经有足够的空闲容量来容纳。

See it run at ideone.com with GCC / C++11.

请参见在ideone.com上运行的GCC / c++ 11。

Now, which computing novice said something about optimisations and evil...? ;-].

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

#1


62  

No, the return value of a function is an l-value if and only if it is a reference (C++03). (5.2.2 [expr.call] / 10)

不,函数的返回值是l值,当且仅当它是引用时(c++ 03)。(5.2.2[expr。调用)/ 10)

If the type returned were a basic type then this would be a compile error. (5.17 [expr.ass] / 1)

如果返回的类型是基本类型,那么这将是一个编译错误。(5.17[expr。屁股]/ 1)

The reason that this works is that you are allowed to call member functions (even non-const member functions) on r-values of class type and the assignment of foo is an implementation defined member function: foo& foo::operator=(const foo&). The restrictions for operators in clause 5 only apply to built-in operators, (5 [expr] / 3), if overload resolution selects an overloaded function call for an operator then the restrictions for that function call apply instead.

这样做的原因是允许您对类类型的r值调用成员函数(甚至非const成员函数),而foo的赋值是一个实现定义的成员函数:foo&foo:operator=(const foo&)。第5条中对操作符的限制仅适用于内置操作符(5 [expr] / 3),如果重载解析为一个操作符选择了一个重载函数调用,那么该函数调用的限制将取而代之。

This is why it is sometimes recommended to return objects of class type as const objects (e.g. const foo q();), however this can have a negative impact in C++0x where it can inhibit move semantics from working as they should.

这就是为什么有时建议将类类型的对象返回为const对象(例如const foo q();),但是这可能会对c++ 0x产生负面影响,在c++ 0x中,这可能会抑制移动语义的正常工作。

#2


8  

Because structs can be assigned to, and your q() returns a copy of struct foo so its assigning the returned struct to the value provided.

因为可以为struct赋值,而q()返回struct foo的副本,因此它将返回的struct赋值给所提供的值。

This doesn't really do anything in this case thought because the struct falls out of scope afterwards and you don't keep a reference to it in the first place so you couldn't do anything with it anyway (in this specific code).

在这种情况下,它不会做任何事情,因为结构体之后会超出范围,而且你不会在一开始就对它进行引用,所以无论如何你都不能对它做任何事情(在这个特定的代码中)。

This makes more sense (though still not really a "best practice")

这更有意义(尽管还不是真正的“最佳实践”)

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

#3


5  

One interesting application of this:

一个有趣的应用是:

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

...

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

Here, g() += modifies the temporary, which may be faster that creating an additional temporary with + because the heap allocated for g()'s return value may already have enough spare capacity to accommodate </tag>.

在这里,g() +=修改临时的,这可能更快地创建一个附加的临时与+,因为为g()的返回值分配的堆可能已经有足够的空闲容量来容纳。

See it run at ideone.com with GCC / C++11.

请参见在ideone.com上运行的GCC / c++ 11。

Now, which computing novice said something about optimisations and evil...? ;-].

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