Правильный способ (переместить семантику) для возврата std :: vector из вызова функции в C ++ 11 - PullRequest
33 голосов
/ 02 июня 2011

Я хочу заполнить std :: vector (или какой-либо другой контейнер STL):

class Foo {
public:
  Foo(int _n, const Bar &_m);
private:
  std::vector<Foo> fooes_;
}

1.Корпус хорошего качества, высокая производительность

std::vector<Foo> get_vector(int _n, const Bar &_m) {
  std::vector<Foo> ret;
  ... // filling ret depending from arguments
  return ret;
}

Foo::Foo(int _n, const Bar &_m) : fooes_(get_vector(_n, _m) {}

2. Лучшая производительность, хуже выглядящий ctor

void fill_vector(int _n, const Bar &_m, std::vector<Foo> &_ret) {
  ... // filling ret depending from arguments
}

Foo::Foo(int _n, const Bar &_m) { fill_vector(_n, _m, fooes_); }

Можно ли переписать функцию get_vector из первого примера на C ++ 0x (переместить функции семантики и т. Д.), Чтобы избежать избыточного копирования и вызовов конструктора?

Ответы [ 3 ]

46 голосов
/ 02 июня 2011

Если вы используете C ++ 0x-совместимый компилятор и стандартную библиотеку, вы получите лучшую производительность из первого примера , ничего не делая .Возвращаемое значение get_vector(_n, _m) является временным, и конструктор перемещения для std::vector (конструктор принимает ссылку на rvalue) будет автоматически вызываться без дальнейшей работы с вашей стороны.

В общем случаеавторам библиотек не нужно напрямую использовать ссылки на rvalue;вы просто автоматически пожнете приличную часть преимуществ.

16 голосов
/ 02 июня 2011

Я считаю, что (1) и (2) имеют одинаковую производительность даже без C ++ 0x, если ваш компилятор выполняет оптимизацию именованных возвращаемых значений, что, как я полагаю, большинство делает. Ни копий, ни , ни ходов .

не должно быть.

Пожалуйста, поправьте меня, если я ошибаюсь, потому что если это так, я неправильно понимаю NRVO.

7 голосов
/ 02 июня 2011

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

...