为什么我可以分配一个返回值的函数的结果?它是左值吗?

发布于 2024-11-10 01:01:14 字数 271 浏览 3 评论 0原文

考虑一下这段代码:

struct foo {
  int a;
};
     
foo q() {
  foo f;
  f.a = 4;
  return f;
}
     
int main() {
  foo i;
  i.a = 5;
  q() = i;
}

没有编译器抱怨它,甚至 Clang 也是如此。为什么 q() = ... 语句是正确的?

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 is the statement q() = ... correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

白衬杉格子梦 2024-11-17 01:01:14

不,函数的返回值当且仅当它是引用时才是左值 (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,它可以阻止移动语义正常工作。

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)

If the type returned were a basic type then this would be a compile error. (5.17 [expr.ass] / 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.

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.

撧情箌佬 2024-11-17 01:01:14

因为可以分配结构体,并且您的 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;
}

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.

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;
}
吹泡泡o 2024-11-17 01:01:14

一个有趣的应用:

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

...

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

这里,g() += 修改临时文件,这可能比使用 + 创建附加临时文件更快,因为为 g() 分配了堆的返回值可能已经有足够的空闲容量来容纳

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

现在,哪个计算新手说了一些关于优化和邪恶的事情……? ;-]。

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>.

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

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

摇划花蜜的午后 2024-11-17 01:01:14

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

On top of other good answers, I'd like to point out that std::tie works on top of this mechanism for unpacking data from another function. See here. So it's not error-prone per se, just keep in mind that it could be a useful design pattern

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文