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

假设我们有以下代码:

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

std::vector<int> x = ...
x = f();

这里的编译器似乎有两种方法:

It seems the compiler has two approaches here:

(a) NRVO:破坏 x,然后构造 f() 代替 x.
(b) 移动:在临时空间构造 f(),将 f() 移动到 x,析构 f().

(a) NRVO: Destruct x, then construct f() in place of x.
(b) Move: Construct f() in temp space, move f() into x, destruct f().

根据标准,编译器是否可以自由使用任一方法?

Is the compiler free to use either approach, according to the standard?

推荐答案

编译器可能会将 NRVO 放入临时空间,或者将构造移动到临时空间.从那里它会移动assign x.

The compiler may NRVO into a temp space, or move construct into a temp space. From there it will move assign x.

更新:

任何时候您想使用右值引用进行优化,并且您对结果不满意时,请为自己创建一个跟踪其状态的示例类:

Any time you're tempted to optimize with rvalue references, and you're not positive of the results, create yourself an example class that keeps track of its state:

  • 构建
  • 默认构造
  • 搬离
  • 销毁

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

And run that class through your test. For example:

#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
";
            break;
        case A::moved_from:
            os << "A is moved from
";
            break;
        case A::default_constructed:
            os << "A is default constructed
";
            break;
        default:
            os << "A = " << a.state_ << '
';
            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;
}

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

If it helps, put print statements in the special members that you're interested in (e.g. copy constructor, move constructor, etc.).

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

Btw, if this segfaults on you, don't worry. It segfaults for me too. Thus this particular design (returning an rvalue reference to a local variable) is not a good design. On your system, instead of segfaulting, it may print out "A is destructed". This would be another sign that you don't want to do this.

相关文章