首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否自动返回xvalue

是否自动返回xvalue
EN

Stack Overflow用户
提问于 2012-04-01 19:25:26
回答 3查看 1.7K关注 0票数 19

以下是我对此所做的评论:

在下面的代码中,为了确保返回值是x值,passing std::vector to constructor and move semantics是必需的std::move吗?

代码语言:javascript
复制
std::vector<string> buildVector()
{
  std::vector<string> local;

  // .... build a vector

  return std::move(local);
}

我的理解是这是必需的。我经常看到在从函数返回std::unique_ptr时使用它,但是GManNickG做了以下评论:

我的理解是,在返回语句中,所有的局部变量都是自动的xvalue(期满值),并将被移动,但我不确定这是否只适用于返回的对象本身。所以OP应该继续把它放进去,直到我更确信它不应该是这样的。:)

有没有人能澄清std::move是否是必要的?

行为编译器是依赖的吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-04-01 19:29:56

在这种情况下,您可以保证local将作为一个右值返回。通常,编译器会执行返回值优化,但在这成为问题之前,您可能根本看不到任何实际的移动,因为local对象将直接在调用点构造。

6.6.3 "The return statement"中的相关说明

为了在选择构造函数(12.8)时解决重载问题,可以省略或与return语句相关的复制或移动操作,或将其视为右值

为了澄清,这是说返回的对象可以从本地对象移动构造(即使在实践中RVO会完全跳过这一步)。该标准的标准部分是12.8 "Copying and moving class objects",关于副本省略和右值(感谢@Mankarse!)。

下面是一个愚蠢的例子:

代码语言:javascript
复制
#include <utility>

struct Foo
{
    Foo()            = default;
    Foo(Foo const &) = delete;
    Foo(Foo &&)      = default;
};

Foo f(Foo & x)
{
    Foo y;

    // return x;         // error: use of deleted function ‘Foo::Foo(const Foo&)’
    return std::move(x); // OK
    return std::move(y); // OK
    return y;            // OK (!!)
}

这与返回实际的右值引用形成对比:

代码语言:javascript
复制
Foo && g()
{
    Foo y;
    // return y;         // error: cannot bind ‘Foo’ lvalue to ‘Foo&&’
    return std::move(y); // OK type-wise (but undefined behaviour, thanks @GMNG)
}
票数 17
EN

Stack Overflow用户

发布于 2012-04-01 20:11:29

虽然return std::move(local)return local都是在编译的意义上工作,但他们的行为是不同的。而且可能只有后者是故意的。

如果你写一个返回std::vector<string>的函数,你必须返回一个std::vector<string>std::move(local)的类型为std::vector<string>&&,它是而不是a std::vector<string>,因此必须使用move构造函数将其转换为它。

该标准在6.6.3.2中规定:

表达式的值被隐式转换为出现表达式的函数的返回类型。

也就是说,return std::move(local)等同于

代码语言:javascript
复制
std::vector<std::string> converted(std::move(local); // move constructor
return converted; // not yet a copy constructor call (which will be elided anyway)

而只有return local才是

代码语言:javascript
复制
return local; // not yet a copy constructor call (which will be elided anyway)

这为您节省了一次操作。

给你一个简短的例子来说明这意味着什么:

代码语言:javascript
复制
struct test {
  test() { std::cout << "  construct\n"; }
  test(const test&) { std::cout << "  copy\n"; }
  test(test&&) { std::cout << "  move\n"; }
};

test f1() { test t; return t; }
test f2() { test t; return std::move(t); }

int main()
{
  std::cout << "f1():\n"; test t1 = f1();
  std::cout << "f2():\n"; test t2 = f2();
}

这将输出

代码语言:javascript
复制
f1():
  construct
f2():
  construct
  move
票数 8
EN

Stack Overflow用户

发布于 2012-04-01 19:45:58

我认为答案是否定的。尽管官方只是注释,§5/6总结了什么表达式是/不是xvalue:

如果表达式是x值,则该表达式是

  • 隐式或显式调用函数的结果,其返回类型是对对象类型的右值引用,
  • 转换为对对象类型的右值引用,
  • 是指定非引用类型的非静态数据成员的类成员访问表达式,其中对象表达式是x值,或
  • 是指向成员的指针表达式,其中第一个操作数是x值,第二个操作数是指向数据成员的指针。

< .* >F211

通常,此规则的效果是命名的右值引用被视为左值,对对象的未命名的右值引用被视为rvalue;对函数的右值引用被视为左值,无论是否命名。

第一个要点似乎适用于这里。由于所讨论的函数返回值而不是rvalue引用,因此结果不会是xvalue。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9963974

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档