Для общего использования принимайте аргументы `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 -- теперь это работает
Примечание
Многие распространённые случаи висячих указателей можно поймать статически (см. профиль безопасности времени жизни). Аргументы функций естественным образом живут в течение вызова функции и поэтому имеют меньше проблем со временем жизни.
Контроль
Предложить использовать T* или T&.
Предложить использовать T* или T&.
- (Простой) Предупреждать, если функция принимает параметр типа умного указателя (который перегружает
operator->илиoperator*), который можно скопировать, но функция использует только:operator*,operator->илиget(). - Помечать параметр типа умного указателя (тип, который перегружает
operator->илиoperator*), который можно скопировать/переместить, но никогда не копируется/перемещается в теле функции, не изменяется и не передаётся другой функции, которая могла бы это сделать. Это означает, что семантика владения не используется.
Смотрите также: