移动或命名返回值优化(NRVO)?

Cli*_*ton 32 c++ optimization move-semantics return-value-optimization c++11

可以说我们有以下代码:

std::vector<int> f()
{
  std::vector<int> y;
  ...
  return y;
} 

std::vector<int> x = ...
x = f();
Run Code Online (Sandbox Code Playgroud)

看来编译器有两种方法:

(a)NRVO:Destruct x,然后构造f()代替x.
(b)移动:在temp空间中构造f(),将f()移动到x,destruct f().

根据标准,编译器是否可以自由使用这两种方法?

How*_*ant 41

编译器可以NRVO进入临时空间,或将构造移动到临时空间.从那里它将移动分配x.

更新:

任何时候你都试图用rvalue引用进行优化,并且你对结果没有好处,那么创建一个跟踪其状态的示例类:

  • 建造
  • 默认构造
  • 离开了
  • 自毁

并通过测试运行该课程.例如:

#include <iostream>
#include <cassert>

class A
{
    int state_;
public:
    enum {destructed = -2, moved_from, default_constructed};

    A() : state_(default_constructed) {}
    A(const A& a) : state_(a.state_) {}
    A& operator=(const A& a) {state_ = a.state_; return *this;}
    A(A&& a) : state_(a.state_) {a.state_ = moved_from;}
    A& operator=(A&& a)
        {state_ = a.state_; a.state_ = moved_from; return *this;}
    ~A() {state_ = destructed;}

    explicit A(int s) : state_(s) {assert(state_ > default_constructed);}

    friend
    std::ostream&
    operator<<(std::ostream& os, const A& a)
    {
        switch (a.state_)
        {
        case A::destructed:
            os << "A is destructed\n";
            break;
        case A::moved_from:
            os << "A is moved from\n";
            break;
        case A::default_constructed:
            os << "A is default constructed\n";
            break;
        default:
            os << "A = " << a.state_ << '\n';
            break;
        }
        return os;
    }

    friend bool operator==(const A& x, const A& y)
        {return x.state_ == y.state_;}
    friend bool operator<(const A& x, const A& y)
        {return x.state_ < y.state_;}
};

A&& f()
{
    A y;
    return std::move(y);
}

int main()
{
    A a = f();
    std::cout << a;
}
Run Code Online (Sandbox Code Playgroud)

如果有帮助,请将print语句放在您感兴趣的特殊成员中(例如复制构造函数,移动构造函数等).

顺便说一下,如果这个段落错误,请不要担心.它也是我的错误.因此,这种特殊设计(返回对局部变量的右值引用)并不是一个好的设计.在您的系统上,它可能会打印出"A is destructed"而不是segfaulting.这将是您不想这样做的另一个迹象.

  • 我故意在答案中使用了OP的术语.该标准力求精确,但是是一个糟糕的教程.我没有(现在仍然没有)认出我是模糊的.这当然是一种常见的失败,我无法免疫.我很乐意澄清我是否知道答案的哪些部分含糊不清.我的目标是传播知识,而不是让它变得混乱. (38认同)