Произойдет ли RVO при возврате std :: pair?

Функция должна вернуть вызывающей стороне два значения. Каков наилучший способ реализации?

Опция 1:

pair<U,V> myfunc()
{
...
return make_pair(getU(),getV());
}

pair<U,V> mypair = myfunc();

Вариант 1.1:

// Same defn
U u; V v;
tie(u,v) = myfunc();

Вариант 2:

void myfunc(U& u , V& v)
{
u = getU(); v= getV();
}

U u; V v;
myfunc(u,v);

Я знаю с Option2, нет никаких копий / ходов, но это выглядит некрасиво. Будут ли какие-либо копии / перемещения происходить в Варианте 1, 1.1? Предположим, что U и V — огромные объекты, поддерживающие обе операции копирования / перемещения.

Вопрос: теоретически возможно ли для какой-либо оптимизации RVO / NRVO согласно стандарту? Если да, реализован ли gcc или любой другой компилятор?

7

Решение

Произойдет ли RVO при возвращении std::pair?

Да, оно может.

Это гарантированно произойдет?

Нет.


Стандарт C ++ 11: раздел 12.8 / 31:

При соблюдении определенных критериев реализация может опустить конструкцию копирования / перемещения объекта класса, даже если конструктор копирования / перемещения и / или деструктор для объекта имеют побочные эффекты.

Копирование elision не является гарантированной функцией. Это оптимизация компиляторов разрешено выполнять всякий раз, когда они могут. В этом нет ничего особенного std::pair, Если компилятор достаточно хорош, чтобы обнаружить возможность оптимизации, он это сделает. Так что ваш вопрос зависит от компилятора, но да, то же правило относится к std::pair как и для любого другого класса.

8

Другие решения

Хотя RVO не гарантируется, в C ++ 11 функция, как вы ее определили, я ДОЛЖНА, по крайней мере, ДОЛЖНА переместить-вернуть, поэтому я бы предложил оставить более четкое определение, а не деформировать его, чтобы принимать выходные переменные (если у вас нет конкретная политика их использования).

Кроме того, даже если в этом примере использовался RVO, ваше явное использование make_pair означает, что у вас всегда будет хотя бы одна дополнительная конструкция пары и, следовательно, операция перемещения. Измените его, чтобы оно возвращало инициализированное скобками выражение:

return { getU(), getV() };
4

Разрешение RVO или Copy зависит от компилятора, поэтому, если вы хотите использовать RVO и избегать вызова конструктора Copy, лучше всего использовать указатели.

В нашем продукте мы используем указатели и указатели контейнеров повышения, чтобы избежать конструктора копирования. и это действительно дает прирост производительности примерно на 10%.

Подойдя к вашему вопросу,
В варианте 1 U и V конструктор копирования не будет вызываться, так как вы не возвращаете U или V, а возвращаете объект std :: pair, поэтому будет вызван его конструктор копирования, и большинство компиляторов определенно будут использовать здесь RVO, чтобы избежать этого.

Спасибо
Нирадж Рати

1
По вопросам рекламы [email protected]