微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 在无法完成RVO的情况下,我们应该写`std :: move`吗?

众所周知,std :: move不应该应用于函数返回值,因为它可以阻止RVO(返回值优化).我感兴趣的是,如果我们确实知道RVO不会发生,我们应该怎么做.

这就是C 14标准所说的[12.8 / 32]

When the criteria for elision of a copy/move operation are met,but
not for an exception-declaration,and the object to be copied is
designated by an lvalue,or when the expression in a return statement
is a (possibly parenthesized) id-expression that names an object with
automatic storage duration declared in the body or
parameter-declaration-clause of the innermost enclosing function or
lambda-expression,overload resolution to select the constructor for
the copy is first performed as if the object were designated by an
rvalue. If the first overload resolution fails or was not performed,
or if the type of the first parameter of the selected constructor is
not an rvalue reference to the object’s type (possibly cv-qualified),
overload resolution is performed again,considering the object as an
lvalue. [ Note: This two-stage overload resolution must be performed
regardless of whether copy elision will occur. It determines the
constructor to be called if elision is not performed,and the selected
constructor must be accessible even if the call is elided. — end note
]

以下是Effective Modern C一书中的解释

The part of the Standard blessing the RVO goes on to say that if the
conditions for the RVO are met,but compilers choose not to perform
copy elision,the object being returned must be treated as an rvalue.
In effect,the Standard requires that when the RVO is permitted,
either copy elision takes place or std::move is implicitly applied to
local objects being returned

据我所知,当返回物体最初不能被省略时,它应被视为右值.在这些示例中,我们可以看到,当我们传递大于5的参数时,移动了对象,否则会被复制.当我们知道RVO不会发生时,这是否意味着我们应该明确地写std :: move?

#include <iostream>
#include <string>


struct Test
{
    test() {}

    Test(const Test& other)
    {
        std::cout << "Test(const Test&)" << std::endl;
    }

    Test(Test&& other)
    {
        std::cout << "Test(const Test&&)" << std::endl;
    }
};

Test foo(int param)
{
    Test test1;
    Test test2;
    return param > 5 ? std::move(test1) : test2;
}

int main()
{
    Test res = foo(2);
}

该程序的输出是Test(const Test&).

解决方法

您的示例中发生的事情与RVO无关,而与三元运算符无关?如果使用if语句重写示例代码,程序的行为将是预期的行为.将foo定义更改为:
Test foo(int param)
  {
  Test test1;
  Test test2;
  if (param > 5)
    return std::move(test2);
  else
    return test1;
  }

输出Test(Test&&).

如果你写(param> 5)会发生什么?std :: move(test1):test2是:

>三元运算符结果推导为prvalue [expr.cond]/5
>然后test2通过lvalue-to-rvalue转换,根据[expr.cond]/6的要求导致copy-initialization
>然后返回值的移动构造被省略[class.copy]/31.3

因此,在您的示例代码中,移动elision发生,然而在形成三元运算符的结果所需的复制初始化之后.

原文地址:https://www.jb51.cc/c/117959.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐