Для общего использования принимайте аргументы `T*` или `T&`, а не умные указатели
Причина
Передача умного указателя передаёт или разделяет владение и должна использоваться только тогда, когда подразумевается семантика владения. Функция, не управляющая временем жизни объекта, должна принимать сырые указатели или ссылки.
Передача через умный указатель ограничивает использование функции только теми вызывающими, кто использует умные указатели. Функция, которой нужен widget, должна принимать любой объект widget, а не только те, чьим временем жизни управляет конкретный вид умного указателя.
Передача разделяемого умного указателя (например, std::shared_ptr) влечёт накладные расходы во время выполнения.
Пример
// принимает любой int*
void f(int*);
// принимает только int-ы, владение которыми вы хотите передать
void g(unique_ptr<int>);
// принимает только int-ы, владением которыми вы готовы поделиться
void g(shared_ptr<int>);
// не изменяет владение, но требует конкретного владения от вызывающего
void h(const unique_ptr<int>&);
// принимает любой int
void h(int&);Пример (плохой)
// вызываемая функция
void f(shared_ptr<widget>& w)
{
// ...
use(*w); // единственное использование w -- время жизни вообще не задействовано
// ...
};
// вызывающий
shared_ptr<widget> my_widget = /* ... */;
f(my_widget);
widget stack_widget;
f(stack_widget); // ошибкаПример (хороший)
// вызываемая функция
void f(widget& w)
{
// ...
use(w);
// ...
};
// вызывающий
shared_ptr<widget> my_widget = /* ... */;
f(*my_widget);
widget stack_widget;
f(stack_widget); // ok -- теперь это работаетПримечание
Многие распространённые случаи висячих указателей можно поймать статически (см. профиль безопасности времени жизни). Аргументы функций естественным образом живут в течение вызова функции и поэтому имеют меньше проблем со временем жизни.
Контроль
- (Простой) Предупреждать, если функция принимает параметр типа умного указателя (который перегружает
operator->илиoperator*), который можно скопировать, но функция использует только:operator*,operator->илиget(). Предложить использоватьT*илиT&. - Помечать параметр типа умного указателя (тип, который перегружает
operator->илиoperator*), который можно скопировать/переместить, но никогда не копируется/перемещается в теле функции, не изменяется и не передаётся другой функции, которая могла бы это сделать. Это означает, что семантика владения не используется. Предложить использоватьT*илиT&.
Смотрите также: