Это быстрее, чтобы вернуть значение или изменить параметр, переданный по ссылке? - PullRequest
9 голосов
/ 03 ноября 2011

В программе, которую я пишу, я должен передавать большие структуры данных (изображения) между функциями. Мне нужно, чтобы мой код был максимально быстрым на разных ОС (поэтому я не могу профилировать все тестовые случаи). У меня часто есть код вида ...

void foo() {
  ImageType img = getCustomImage();
}

ImageType getCustomImage() {
  ImageType custom_img;
  //lots of code
  return custom_img;
}

AFAIK, строка ImageType img = getCustomImage(); приведет к вызову конструктора копирования для img с возвращаемым значением из custom_img в качестве параметра. Википедия говорит, что некоторые компиляторы даже сделают эту операцию снова для начальной временной переменной!

Мой вопрос: быстрее ли вообще обходить эти издержки (конструкторы копирования для изображений стоят дорого), используя передачу по ссылке, а не возвращаемое значение ...

void foo() {
  ImageType img;
  getCustomImage(img);
}

void getCustomImage(ImageType &img) {
  //code operating directly on img
}

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

Ответы [ 4 ]

13 голосов
/ 03 ноября 2011

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

Вы правы в том, логически код запускаетразличные конструкции копирования: от custom_img до возвращенного временного объекта и затем до объекта img в коде вызывающей стороны, но факт заключается в том, что обе копии будут исключены.

В частном случае возврат по значению против конструкция по умолчанию + передача по ссылке , все соглашения о вызовах, которые я знаю о реализации , возвращают по значению , если вызывающая сторона выделяет память и передаетскрытый указатель на вызываемого, который эффективно реализует то, что вы пытаетесь сделать.Таким образом, с точки зрения производительности, они в основном эквивалентны.

Я писал об этом (семантика значений в аргументах функций и возвращаемых значениях) в прошлом в этих двух записях блога:

РЕДАКТИРОВАТЬ : я намеренно избегал обсужденияслучаи, когда NRVO не может быть применен компилятором, причина в том, что любая функция f, которая может принимать ссылку на объект для обработки: void f( T & out ) { /* code */ }, может быть тривиально преобразована в функцию, где NRVO тривиально для компилятора, чтобы реализовать этовозвращает значение путем простого преобразования в: T f() { T out; /* code */ return out; }

1 голос
/ 03 ноября 2011

По крайней мере, если вы ориентируетесь на достаточно современные компиляторы для достаточно типичных ОС, таких как Windows, MacOS, Linux или * BSD, вы вполне можете рассчитывать на их реализацию RVO / NRVO. В любом случае, вам нужно было бы выглядеть довольно трудно, чтобы найти случаи, когда было достаточно различий, чтобы о них заботиться, или, скорее всего, вообще.

В зависимости от того, как вы используете задействованные данные, при наличии разницы в скорости он может почти так же легко отдавать предпочтение передаче / возврату объектов, как и использование ссылки. Возможно, вы захотите прочитать об этом статью Дэвида Абрахамса

.
1 голос
/ 03 ноября 2011

, поскольку ваши изображения представляют собой большие структуры данных, я, возможно, предположил бы, что функция должна возвращать указатели на изображения.Вы также можете использовать ссылки (которые на машинном уровне являются указателями), но я думаю, что указатели лучше подходят для этой цели.

Я больше знаком с C, чем с C ++, поэтому могу ошибаться.

Важным вопросом является то, когда и кем должны быть перераспределены ваши изображения.

0 голосов
/ 03 ноября 2011

Видя вопрос «Что быстрее?», Я обычно советую на самом деле измерить для себя, в своем компиляторе / среде, а затем выяснить, почему это так.

...