Оптимизация перемещения или именованного возвращаемого значения (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().

Является ли компилятор свободным для использования любого из подходов в соответствии со стандартом?

1 ответ

Решение

Компилятор может 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;
}

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

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

Другие вопросы по тегам