Функция должна вернуть вызывающей стороне два значения. Каков наилучший способ реализации?
Опция 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 или любой другой компилятор?
Произойдет ли RVO при возвращении
std::pair
?
Да, оно может.
Это гарантированно произойдет?
Нет.
Стандарт C ++ 11: раздел 12.8 / 31:
При соблюдении определенных критериев реализация может опустить конструкцию копирования / перемещения объекта класса, даже если конструктор копирования / перемещения и / или деструктор для объекта имеют побочные эффекты.
Копирование elision не является гарантированной функцией. Это оптимизация компиляторов разрешено выполнять всякий раз, когда они могут. В этом нет ничего особенного std::pair
, Если компилятор достаточно хорош, чтобы обнаружить возможность оптимизации, он это сделает. Так что ваш вопрос зависит от компилятора, но да, то же правило относится к std::pair
как и для любого другого класса.
Хотя RVO не гарантируется, в C ++ 11 функция, как вы ее определили, я ДОЛЖНА, по крайней мере, ДОЛЖНА переместить-вернуть, поэтому я бы предложил оставить более четкое определение, а не деформировать его, чтобы принимать выходные переменные (если у вас нет конкретная политика их использования).
Кроме того, даже если в этом примере использовался RVO, ваше явное использование make_pair означает, что у вас всегда будет хотя бы одна дополнительная конструкция пары и, следовательно, операция перемещения. Измените его, чтобы оно возвращало инициализированное скобками выражение:
return { getU(), getV() };
Разрешение RVO или Copy зависит от компилятора, поэтому, если вы хотите использовать RVO и избегать вызова конструктора Copy, лучше всего использовать указатели.
В нашем продукте мы используем указатели и указатели контейнеров повышения, чтобы избежать конструктора копирования. и это действительно дает прирост производительности примерно на 10%.
Подойдя к вашему вопросу,
В варианте 1 U и V конструктор копирования не будет вызываться, так как вы не возвращаете U или V, а возвращаете объект std :: pair, поэтому будет вызван его конструктор копирования, и большинство компиляторов определенно будут использовать здесь RVO, чтобы избежать этого.
Спасибо
Нирадж Рати