2013-06-28 5 views
16

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

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

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

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

становится

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

где MyAnimal мой новый класс обертка герметизирующего AnimalPtr.

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

+0

В целом, хранение ссылок на интеллектуальные указатели не является хорошей идеей, но передача ссылки на нее, когда вы знаете, что она не будет сохранена, обычно нормально, см. Например, этот вопрос: http: // stackoverflow.com/questions/179105/why-shouldnt-you-use-references-to-smart-pointers – confusopoly

ответ

22

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

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

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

+1

На самом деле, я вроде как принимаю 'std :: unique_ptr const &' - это означает, что это принадлежащий ему объект, и нет, вы не можете этого сделать. Аналогично, 'std :: unique_ptr &' означает, что это принадлежащий ему объект, но вы можете изменить это право собственности, если хотите. С другой стороны, мне также нравится «pass-through» unique_ptr', где вы берете значение «unique_ptr» по значению и возвращаете его по значению в возвращаемом значении ... – Yakk

+3

@Yakk: 'std :: unique_ptr const &' заставляет ваш выбор умного указателя на ваших пользователей и блокирует вызовы с объектами, которые не управляются с помощью 'std :: unique_ptr', излишне, передача' T & 'явно означает, что он является * принадлежащим * (кем-то, где-то) объектом и более гибким (помимо включения уровня const-correctness, вы не можете получить с помощью 'const &' для умного указателя. Передача 'std :: unique_ptr &' непонятно на вызывающем абоненте относительно того, остается ли объект моим или вашим, или я могу использовать указатель после вызова? –

+0

@Yakk: Да, я не говорю о техническом состоянии его обнаружения, а скорее при написании кода. Имеет ли смысл с точки зрения дизайна иметь функцию, которая может или может ot претензии собственности? Имеет ли смысл внедрять функцию, которая вызывает его, и что в некоторых случаях для работы над объектом есть некоторая работа после вызова, но что также не нужно ничего делать? Я бы нашел, что этот код трудно пройти через проверку кода, если не существует очень сильной причины делать что-то таким запутанным образом. –

3

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

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

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

+0

Вы можете создать копию указателя на объект в любое время: 'Foo * f = smart_foo.get()', и вы не можете гарантировать время жизни 'f'. – Chad

+0

@chad - Да, указатель на интеллектуальный указатель всегда небезопасен. Но вопрос был о ссылках против не-ссылок, и это ничем не отличается для этих двух. – JoshG79