移动或命名返回值优化(NRVO)? [英] Move or Named Return Value Optimization (NRVO)?

查看:106
本文介绍了移动或命名返回值优化(NRVO)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有以下代码:

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

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

似乎编译器有两种方法:



(a)NRVO:Destruct x,然后构造f()代替x。

(b)Move:在临时空间中构造f ()。



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

解决方案

编译器可以将NRVO转换为一个临时空间,或将结构移动到临时空间。从那里它会移动分配 x



更新: b
$ b

任何时候,如果你试图使用右值引用进行优化,并且你对结果不满意,可以创建一个跟踪其状态的示例类:




  • 构建

  • 默认构造

  • b
  • 破坏



通过测试运行该类。例如:

  #include< iostream> 
#include< cassert>

class A
{
int state_;
public:
枚举{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_;返回* this;}
A(A& a):state_(a.state_){a.state_ = moved_from;}
A& operator =(A& a)
{state_ = a.state_; a.state_ = moved_from;返回* 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从\\\
移动;
break;
case A :: default_constructed:
os<< A is default constructed \\\
;
break;
默认值:
os<< A =< a.state_< '\\\
';
break;
}
return os;
}

friend bool operator ==(const A& x,const A& y)
{return x.state_ == y.state_;}
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<<一个;
}

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



Btw,如果这个segfaults对你,不要担心。它segfaults为我。因此,这个特定的设计(将一个右值引用返回一个局部变量)不是一个好的设计。在您的系统上,而不是segfaulting,它可能会打印出A is destructed。这是另一个迹象,你不想这样做。


Lets say we have the following code:

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: 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?

解决方案

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

Update:

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:

  • constructed
  • default constructed
  • moved from
  • destructed

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\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;
}

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

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.

这篇关于移动或命名返回值优化(NRVO)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆