Оптимизация возвращаемого значения члена локальной переменной стека - PullRequest
0 голосов
/ 10 июня 2018

У меня есть фрагмент общего кода, который при создании экземпляра сводится к:

struct A{...};

A f1(){
    A ret;
    std::pair<A&, int> p(ret, 1);
    p = g(); // g returns a pair<A, int>, but I am not interested in g
    return ret; // RVO :)
};

Насколько я понимаю, это будет работать с RVO.

вопрос в том, будет ли этот другой код возвращать объект типа A с RVO?

A f2(){
    std::pair<A, int> p;
    p = g();
    return p.first; // RVO ?
};

Я понимаю, что, поскольку возвращаемый объект скрыт, он не будет выполнять RVO или компилятор можетне сможет подобрать «оптимизацию».Но я не вижу фундаментальной причины, по которой это было бы невозможно, другими словами, я думаю, для последовательности, это должно сделать RVO (что я хочу).

Причина, по которой я спрашиваю, это потому, что ядумаю, f2 более элегантный код, чем f1.

Должна ли эта последняя версия выполнять RVO?Если да, зависит ли это от компилятора?


Мой грубый тест с gcc 8.1 показывает, что RVO не работает в f2 и f3 ниже:

struct A{
    double something;
    A() = default;
    A(A const& other) : something(other.something){std::cerr << "cc" << '\n';}
    A(A&& other) : something(other.something){std::cerr << "mc" << '\n';}
};

A f1(){
    A ret;
    std::pair<A&, int> p(ret, 1);
    p.first.something = 5.;
    return ret; // RVO :)
};

A f2(){
    std::pair<A, int> p;//(ret, 1);
    p.first.something = 5.;
    return p.first; // no RVO :(
};

A f3(){
    std::pair<A, int> p;//(ret, 1);
    p.first.something = 5.;
    return std::move(p).first; // no RVO :(
};


int main(){
    A a1 = f1(); // prints nothing, RVO
    A a2 = f2(); // prints "cc"; no RVO! Why?
    A a3 = f3(); // prints "mc" (no much gain in this case); still no RVO!
}

1 Ответ

0 голосов
/ 10 июня 2018

Чтобы RVO работал, возвращаемое значение должно быть создано в хранилище, где вызывающий ожидает его найти.Возможно, это регистр, имя которого указано соглашением о вызовах, или, возможно, он находится в стеке.

std::pair<A, int> по существу:

struct foo {
    A first;
    int second;
};

Теперь, если необходимо возвращаемое значениедля сохранения в определенном месте с sizeof(A), но пара имеет больший размер, пара не может быть сохранена там.Единственный способ заставить RVO по-прежнему работать, если вызываемый объект знает, что байты sizeof(int), следующие за возвращаемым значением, могут быть засорены во время выполнения функции.Но язык, вероятно, не должен требовать RVO в таком случае, потому что он не может быть реализован в каждом соглашении о вызовах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...