Передача интеллектуальных указателей по ссылке

Смарт-указатели, как правило, крошечные, поэтому передача по значению не является проблемой, но есть ли какие-либо проблемы с передачей ссылок на них; или, вернее, есть конкретные случаи, когда это не должно быть сделано?

Я пишу библиотеку обертки, а некоторые из моих классов переносят объекты smart-pointer в базовую библиотеку... мои классы не являются умными указателями, но API в настоящее время передают объекты интеллектуального указателя по значению.

например текущий код:

void class::method(const AnimalPtr pAnimal) { ... }

становится

void class::method(const MyAnimal &animal){...}

где MyAnimal - мой новый класс оболочки, инкапсулирующий AnimalPtr.

Нет гарантии, что классы Wrapper ни разу не будут расти за пределы смарт-указателя, поэтому переход по значению заставляет меня нервничать.

Ответ 1

В большинстве случаев вы должны передавать общие указатели по ссылке, а не по значению. Хотя размер a std::shared_ptr мал, стоимость копирования включает в себя атомную операцию (концептуально атомный приращение и атомный декремент при уничтожении копии, хотя я считаю, что некоторым реализациям удается выполнить неатомное приращение).

В других случаях, например std::unique_ptr, вы можете предпочесть передавать по значению, так как копия должна быть перемещена, и она четко документирует, что право собственности на объект передается функции (если вы не хотите для передачи права собственности, затем передайте ссылку на реальный объект, а не на std::unique_ptr).

В других случаях ваш пробег может отличаться. Вам нужно знать, что такое семантика копии для вашего умного указателя, и нужно ли платить за ее стоимость или нет.

Ответ 2

Хорошо пропустить смарт-указатель по ссылке, кроме как если бы он был конструктором. В конструкторе можно сохранить ссылку на исходный объект, что нарушает договор интеллектуальных указателей. Если вы это сделаете, вы, вероятно, получите повреждение памяти. Даже если ваш конструктор сегодня не хранит ссылку, я все равно буду опасаться, потому что код изменяется, и легко пропустить, если вы решите позже, вам нужно удерживать эту переменную дольше.

В нормальной функции вы не можете хранить параметр функции как ссылку в любом месте, поскольку ссылки должны быть установлены во время их инициализации. Вы можете назначить ссылку на какую-то более длинную живую переменную, не относящуюся к ссылке, но это будет копия и, соответственно, увеличит ее срок службы. Таким образом, в любом случае вы не могли удержать его в прошлом, когда вызывающая функция могла его освободить. В этом случае вы можете получить небольшое повышение производительности с помощью ссылки, но я бы не стал замечать это в большинстве случаев.

Итак, я бы сказал - конструктор, всегда передаваемый по значению; другие функции, передайте по ссылке, если хотите.