Подтвердить что ты не робот

Правильный способ (переместить семантику), чтобы вернуть std::vector из вызова функции в С++ 11

Я хочу заполнить 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 из первого примера с помощью С++ 0x (функции семантики перемещения и т.д.), чтобы избежать избыточных вызовов копирования и конструктора?

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

Есть некоторые очень специфические обстоятельства, когда перенос вектора в функцию для модификации может быть быстрее, но они редки и более связаны с доменом, чем с самим вектором. Просто игнорируйте это, сначала код для ремонтопригодности, а если программа медленная, профиль, определите, где стоит стоимость программы, и только тогда подумайте об оптимизации. Интересная часть состоит в том, что после того, как вы профилировали, вы, вероятно, знаете, что такое узкое место, и это означает, что у вас будут намеки на то, что нужно изменить.