Подтвердить что ты не робот

Перемещение или Именованная оптимизация возвращаемого значения (NRVO)?

Допустим, у нас есть следующий код:

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

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

Кажется, у компилятора есть два подхода:

(a) NRVO: уничтожить x, затем построить f() вместо x.
(b) Переместить: Построить f() в временном пространстве, переместить f() в x, разрушить f().

Может ли компилятор использовать любой из подходов в соответствии со стандартом?

4b9b3361

Ответ 1

Компилятор может использовать NRVO в временном пространстве или перемещать конструкцию в временное пространство. Оттуда он переместит назначение x.

Update:

В любое время, когда у вас возникает соблазн оптимизировать ссылки 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;
}

Если это помогает, поместите инструкции печати в специальные члены, которые вас интересуют (например, конструктор копирования, перемещение конструктора и т.д.).

Btw, если это вам не поможет, не волнуйтесь. Это тоже для меня. Таким образом, эта конкретная конструкция (возвращающая ссылку rvalue на локальную переменную) не является хорошим дизайном. В вашей системе вместо segfault, он может распечатывать "A разрушен". Это было бы еще одним признаком того, что вы не хотите этого делать.