Ответ 1
Предполагая, что ваша функция конструирует и возвращает новые данные, вы должны вернуться по значению и попытаться убедиться, что сама функция имеет одну точку возврата, которая возвращает переменную типа vector<int>
, или, в худшем случае, несколько точек возврата, которые все возвращают одна и та же переменная.
Это гарантирует, что вы получите оптимизацию значения named для любого достоверного компилятора, который исключает одну из потенциальных копий (одну из значения в функции, возвращаемое значение). Есть и другие способы получить оптимизацию возвращаемого значения, но это не вполне предсказуемо, поэтому простое правило безопасно.
Затем вы хотите исключить потенциальную копию из возвращаемого значения независимо от того, что делает вызывающий абонент. Это проблема вызывающего абонента, а не вызывающая, и есть в основном три способа сделать это:
- Используйте вызов функции как инициализатор для
vector<int>
, и в этом случае снова любой надежный компилятор С++ будет удалять копию. - Используйте С++ 11, где
vector
имеет семантику перемещения. - В С++ 03 используйте "swaptimization".
То есть, в С++ 03 не пишите
vector<int> v;
// use v for some stuff
// ...
// now I want fresh data in v:
v = getLargeArray();
Вместо
getLargeArray().swap(v);
Это позволяет избежать требуемого присваивания копий (не следует указывать [*]) для v = getLargeArray()
. Это не нужно в С++ 11, где вместо дешевого назначения копирования есть дешевое назначение переноса, но, конечно, оно все еще работает.
Еще одна вещь, которую стоит рассмотреть - действительно ли вы хотите vector
как часть вашего интерфейса. Вместо этого вы могли бы написать шаблон функции, который принимает итератор вывода, и записывает данные на этот выходной итератор. Абоненты, которым нужны данные в векторе, могут передать результат std::back_inserter
, и поэтому могут быть абоненты, которым нужны данные в deque
или list
. Звонящие, которые заранее знают размер данных, могут даже передавать только векторный итератор (желательно resize()
d first) или необработанный указатель на достаточно большой массив, чтобы избежать накладных расходов back_insert_iterator
. Существуют нестандартные способы сделать одно и то же, но они, скорее всего, повлекут за собой накладные расходы так или иначе. Если вы беспокоитесь о стоимости копирования int
за элемент, вы беспокоитесь о стоимости вызова функции для каждого элемента.
Если ваша функция не создает и не возвращает новые данные, а возвращает текущее содержимое некоторого существующего vector<int>
и не имеет права изменять оригинал, тогда вы не можете избежать хотя бы одной копии, когда вы возврат по значению. Поэтому, если производительность этого является проверенной проблемой, вам нужно посмотреть на какой-либо API, отличный от возвращаемого значения. Например, вы можете предоставить пару итераторов, которые могут использоваться для перемещения внутренних данных, функции для поиска значения в векторе по индексу или даже (если проблема производительности настолько серьезна, что позволяет подвергать вас внутренности) ссылка на вектор. Очевидно, что во всех этих случаях вы меняете смысл функции - вместо того, чтобы давать вызывающей стороне "свои собственные данные", она дает представление о других данных, которые могут измениться.
[*], конечно, правило "как будто" все еще применяется, и можно представить себе реализацию С++, которая достаточно умна, чтобы понять, что, поскольку это вектор тривиально-скопируемого типа (int
), а так как вы haven "Я принимал какие-либо указатели на какие-либо элементы (я полагаю), тогда он может заменить swap, а результат" как будто "он скопировал. Но я не стал бы рассчитывать на это.