Сколько данных копируется при возврате std :: vector в функцию и насколько велика будет оптимизация, чтобы разместить std :: vector в свободном хранилище (в куче) и вместо этого вернуть указатель, то есть:
std::vector *f()
{
std::vector *result = new std::vector();
/*
Insert elements into result
*/
return result;
}
более эффективно, чем:
std::vector f()
{
std::vector result;
/*
Insert elements into result
*/
return result;
}
?
c++
return-value
stdvector
Мортен
источник
источник
f
?Ответы:
В C ++ 11 это предпочтительный способ:
То есть возврат по значению.
В C ++ 11
std::vector
есть семантика перемещения, что означает, что локальный вектор, объявленный в вашей функции, будет перемещен при возврате, а в некоторых случаях даже перемещение может быть исключено компилятором.источник
return std::move(v);
отключит перемещение-исключение, даже если это было возможно с помощью justreturn v;
. Так что последнее предпочтительнее.Вы должны вернуться по стоимости.
В стандарте есть особенность для повышения эффективности возврата по значению. Это называется «копированием», а конкретнее в данном случае «оптимизацией именованного возвращаемого значения (NRVO)».
Компиляторы не должны реализовывать это, но опять же компиляторы не должны реализовывать встраивание функций (или вообще выполнять какую-либо оптимизацию). Но производительность стандартных библиотек может быть довольно низкой, если компиляторы не оптимизируются, а все серьезные компиляторы реализуют встраивание и NRVO (и другие оптимизации).
Когда применяется NRVO, в следующем коде не будет копирования:
Но пользователь может захотеть сделать это:
Копирование не препятствует копированию здесь, потому что это назначение, а не инициализация. Однако вы все равно должны возвращаться по значению. В C ++ 11 назначение оптимизируется чем-то другим, называемым «семантикой перемещения». В C ++ 03 приведенный выше код действительно вызывает копию, и хотя теоретически оптимизатор может избежать этого, на практике это слишком сложно. Поэтому вместо
myvec = f()
C ++ 03 вы должны написать это:Есть еще один вариант - предложить пользователю более гибкий интерфейс:
Затем вы также можете поддерживать существующий векторный интерфейс, помимо этого:
Это может быть менее эффективным, чем ваш существующий код, если ваш существующий код использует
reserve()
более сложный способ, чем просто фиксированная сумма вперед. Но если ваш существующий код в основном обращаетсяpush_back
к вектору неоднократно, тогда этот код на основе шаблона должен быть таким же хорошим.источник
Пора ответить про RVO , я тоже ...
Если вы возвращаете объект по значению, компилятор часто оптимизирует его, чтобы он не создавался дважды, поскольку излишне создавать его в функции как временное, а затем копировать. Это называется оптимизацией возвращаемого значения: созданный объект будет перемещен, а не скопирован.
источник
Распространенная идиома до C ++ 11 - передавать ссылку на заполняемый объект.
Тогда нет копирования вектора.
источник
Если компилятор поддерживает оптимизацию именованных возвращаемых значений ( http://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx ), вы можете напрямую вернуть вектор при условии, что нет:
NRVO оптимизирует вызовы конструктора избыточной копии и деструктора и, таким образом, улучшает общую производительность.
В вашем примере не должно быть реальной разницы.
источник
И если вы хотите распечатать его в main (), вы должны делать это в цикле.
источник
Каким бы прекрасным ни был «возврат по значению», такой код может привести к ошибке. Рассмотрим следующую программу:
Вышеупомянутая ошибочная программа не будет указывать на ошибки, даже если вы используете параметры отчетности GNU g ++ -Wall -Wextra -Weffc ++
Если вы должны создать значение, то вместо вызова vecFunc () дважды будет работать следующее:
Вышеупомянутое также не создает анонимных объектов во время итерации цикла, но требует возможной операции копирования (которая, как некоторое примечание, может быть оптимизирована при некоторых обстоятельствах. Но ссылочный метод гарантирует, что копия не будет создана. Полагая, что компилятор будет выполнить RVO не заменяет попытки построить наиболее эффективный код, который вы можете. Если вы можете оспорить необходимость компилятора для выполнения RVO, вы впереди всех.
источник
источник