върнати вектор‹Foo› или shared_ptr‹vector‹Foo››?

във функция, кое "връщане" би било по-подходящо?

A. vector<Foo> ?

B. shared_ptr<vector<Foor>> ?

С други думи, кое копие е по-малко тежко, какво бихте направили и защо?


person Alon Amir    schedule 02.11.2011    source източник
comment
Възможен дубликат/свързано: stackoverflow.com/questions /3721217/   -  person larsmoa    schedule 02.11.2011
comment
Проверете своя компилатор, но обикновено можете да предположите, че elision ЩЕ се случи, в който случай връщането по стойност е най-бързият начин. Това е и най-добрият начин за семантика (идемпотентност, присвояване на константен резултат и т.н.), вижте тази статия   -  person spraff    schedule 02.11.2011
comment
И защо unique_ptr не е опция? Връщането на shared_ptr предполага, че функцията запазва копие; връщането на unique_ptr уведомява всички, че собствеността се прехвърля изцяло.   -  person Nicol Bolas    schedule 02.11.2011
comment
@NicolBolas unique_ptr също е опция, както и intrusive_ptr и т.н.. същият въпрос. въпросът е, че изобщо трябва да се използва интелигентен показалец.   -  person Alon Amir    schedule 02.11.2011


Отговори (3)


Мисля, че връщането на shared_ptr<vector<T>> рядко е полезно. Бих направил това само ако няколко обекта държат споделен вектор, който могат да манипулират. За мен това означава грешка в дизайна. По-добра алтернатива вероятно е връщането чрез const препратка. Това избягва (потенциално скъпа) операция за копиране, но не позволява на инструмента за достъп да променя вектора.

Ако връщате локален std::vector, можете също да го върнете чрез аргумент.

Ако наистина искате да върнете shared_ptr<vector<T>>, помислете дали shared_ptr<const vector<T>> ще свърши работа (векторът може да бъде инспектиран от много хора, но само манипулиран от собственика).

Въпреки това A обикновено е по-скъпо от B, но оптимизациите на възвръщаемата стойност често се прилагат тук. За C++11 std::vector има конструктор за преместване, който ще гарантира, че връщането на локален std::vector няма да изисква скъпи операции за копиране.

Запомнете, не оптимизирайте преждевременно :)

person larsmoa    schedule 02.11.2011
comment
Всичко това е игнориране на RVO/NRVO, което прави въпроса спорен на първо място. - person ildjarn; 03.11.2011

Връщането на shared_ptr<vector<Foo>> гарантира, че няма да се появи допълнително копие.

Връщането на vector<Foo> може да избегне допълнително копиране, ако се включи оптимизацията на връщаната стойност (RVO) или ако се използва семантика на преместване от C++11. Но ако е важно да избягвам копирането, не бих използвал това (дори ако можете да гарантирате, че тези оптимизации винаги ще бъдат налични), защото не мисля, че е добра идея да се използва семантика за връщане на копие, докато всъщност означава да не копирате .

Вероятно бих избрал едно от тези, но зависи:

  • подайте препратка към vector<Foo> като параметър
  • вместо това подайте итератор на вмъкване (напр. back_inserter).
person hamstergene    schedule 02.11.2011
comment
относно препратката: Точно така, защото тя ще бъде унищожена в края на обхвата на функцията. Компилирам кръстосано върху различни платформи, ios, използвайки xCode, vs2010. какво препоръчваш тогава? - person Alon Amir; 02.11.2011
comment
@AlonAmir Вижте актуализирания отговор. Ако избягването на копиране е важно, не предавайте vector по стойност. - person hamstergene; 02.11.2011
comment
предаване на препратка към vector<Foo> като параметър: Не бих, ако функцията създава вектора вътрешно, тогава това е върната стойност. Конвенцията за извикване за всички компилатори, за които знам, в случай на тип връщане, който не се побира в регистрите, ще приложи това за вас: извикващият разпределя пространството и предава указател към извиквания, след това извикваният инициализира тази памет с реален обект (извикване на подходящия конструктор в зависимост от кода). Ефектът е, че получавате по-чист интерфейс с абсолютно същата цена. - person David Rodríguez - dribeas; 02.11.2011
comment
@DavidRodríguez-dribeas Добре, точно това се опитвам да избегна, правейки функции, които получават параметри. - person Alon Amir; 02.11.2011

В C++03 предпочитайте:

  1. Ако предоставяте достъп до член, върнете чрез const препратка.
  2. В противен случай, ако връщате локален, използвайте изходящ референтен параметър.

В C++11 предпочитайте:

  1. Ако предоставяте достъп до член, върнете чрез const препратка.
  2. В противен случай, ако връщате локално, върнете по стойност, тъй като конструкцията на преместване ще избегне прекомерни копия.

Ситуацията, в която бихте искали да върнете интелигентен указател с преброени референции, би била, когато множество обекти с различни времена на живот всички ще искат достъп до обекта. Това обаче не е най-честият сценарий, но се случва достатъчно често.

person Michael Price    schedule 03.11.2011
comment
Не съм съгласен и с двете предложения #2. Copy elision/RVO/каквото-искат-да-нарекат-това може да направи много връщане на контейнери евтино. Освен ако не връщате временно, конструкторите за преместване ще бъдат извикани само ако изрично ги поискате чрез std::move. Така или иначе е по-добре да използвате elision за копиране. - person Nicol Bolas; 03.11.2011
comment
C++03: никога не връщате препратка към локална променлива. - person Barney Szabolcs; 15.12.2012
comment
@BarnabasSzabolcs - Трябва да анализирате езика ми по-внимателно. Ако нещото, което ще върнете, ще бъде локално за функцията, тогава предайте екземпляр на обекта чрез препратка като параметър вместо това. - person Michael Price; 10.01.2013