Ответ 1
Возвратить интеллектуальные указатели по значению.
Как вы уже сказали, если вы вернете его по ссылке, вы не будете правильно увеличивать счетчик ссылок, что открывает риск удаления чего-либо в ненадлежащее время. Это само по себе должно быть достаточным основанием для отказа от ссылки. Интерфейсы должны быть надежными.
В настоящее время беспокойство по поводу затрат вызывает беспокойство благодаря оптимизации возвращаемого значения (RVO), поэтому вы не будете следовать последовательности инкремент-инкремент-декремент или что-то подобное в современных компиляторах. Поэтому лучшим способом вернуть shared_ptr
является просто возврат по значению:
shared_ptr<T> Foo()
{
return shared_ptr<T>(/* acquire something */);
};
Это мертво-очевидная возможность RVO для современных компиляторов С++. Я знаю, что компиляторы Visual С++ реализуют RVO, даже когда все оптимизации отключены. И с семантикой перемещения С++ 11 эта проблема еще менее актуальна. (Но единственный способ быть уверенным в том, чтобы профилировать и экспериментировать.)
Если вы все еще не уверены, у Дейва Абрахама есть статья, в которой аргумент возвращается по значению. Здесь я воспроизвожу фрагмент; Я настоятельно рекомендую вам прочитать всю статью:
Будьте честны: как выглядит следующий код:
std::vector<std::string> get_names(); ... std::vector<std::string> const names = get_names();
Честно говоря, хотя я должен знать лучше, это заставляет меня нервничать. В принципе, когда
get_names()
возвращается, мы должны скопировать avector
изstring
s. Затем нам нужно скопировать его снова, когда мы инициализируемnames
, и нам нужно уничтожить первую копию. Если в векторе есть Nstring
, каждая копия может потребовать столько же распределений памяти N + 1, сколько целого числа нечетких данных доступа к кэшу > при копировании содержимого строки.Вместо того, чтобы противостоять подобной тревоге, Ive часто отказывался от передачи по ссылке, чтобы избежать ненужные копии:
get_names(std::vector<std::string>& out_param ); ... std::vector<std::string> names; get_names( names );
К сожалению, этот подход далеко не идеален.
- Код вырос на 150%
- Нам пришлось отказаться от
const
-ness, потому что были мутирующие имена.- Как функциональные программисты любят напоминать нам, мутация делает код более сложным для объяснения, подрывая ссылочную прозрачность и эквациональные рассуждения.
- У нас больше нет строгой семантики значений для имен.
Но действительно ли нужно испортить наш код таким образом, чтобы повысить эффективность? К счастью, ответ оказывается отрицательным (и особенно если вы используете С++ 0x).