Эффективность построения контейнера stl на основе возврата функции

У меня есть фабричная функция, которая возвращает контейнер STL:

const std::vector<int> f(...) {
std::vector<int> retval;
return retval;
}

Я думаю, это нормально, чтобы определить экземпляр stl следующим образом (без ошибок):

const std::vector<int> stl_instance(f(...));

Но так ли это эффективно?

Является ли временный объект STL непосредственно назначенным stl_instance?

4

Решение

Возвращение const rvalue является антишаблоном в C ++ 11. Сначала рассмотрим возврат неконстантных значений:

std::vector<int> f(int n)
{
return std::vector<int>(n);
}

int main()
{
std::vector<int> v;
v = f(3);
}

В C ++ 98/03 этот код будет попадать в кучу как минимум дважды:

  1. Создать вектор внутри f (если применяется RVO)
  2. Чтобы назначить от возвращения f к v.

Если ваш компилятор не применяет RVO, вы получаете 3 выделения кучи.

В C ++ 11 вы получаете только 1 выделение кучи: чтобы создать вектор внутри f, Это происходит независимо от RVO. Причина в том, что все контейнеры STL имеют конструкторы перемещения и операторы присваивания перемещения, которые имеют подписи

vector( vector&& other );
vector& operator=( vector&& other );

Rvalue ссылки && переместит ресурсы из вашей функции создания прямо в место назначения. Тем не менее, ваш код имеет подпись

const std::vector<int> f(int n)
{
return std::vector<int>(n);
}

отключит семантику перемещения, потому что T&& (то есть аргумент конструктора перемещения и оператора присваивания) не будет привязываться к параметру const rvalue (то есть к возвращаемому значению вашей функции). Это эффективно заставляет ваш код работать как в C ++ 98/03 (то есть с 2 или 3 выделениями кучи).

5

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

Это прекрасный и юридический код.
Компилятор позаботится о необходимых оптимизациях (если может) через копию elision.

Временный f(...) гарантированно проживет, по крайней мере, до конца выражения. Обратите внимание, что выражения заканчиваются сразу после возврата из stl_instance(f(...)), точнее ;(точка с запятой в конце вызова). Так что это совершенно верно.

Стандарт C ++ 03 §12.2 / 3:

Временные объекты уничтожаются как последний шаг в оценке полного выражения (1.9), которое (лексически) содержит точку, где они были созданы.

1

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