Никогда не передавайте владение через сырой указатель (`T*`) или ссылку (`T&`)
Причина
Если есть какие-либо сомнения в том, кто владеет объектом — вызывающая или вызываемая сторона, — произойдут утечки или преждевременное уничтожение.
Пример
Рассмотрим:
X* compute(args) // не делайте так
{
X* res = new X{};
// ...
return res;
}
Кто удаляет возвращённый X? Проблему было бы сложнее обнаружить, если бы compute вернул ссылку. Рассмотрите возврат результата по значению (используйте семантику перемещения, если результат большой):
vector<double> compute(args) // хорошо
{
vector<double> res(10000);
// ...
return res;
}
Альтернатива: Передавайте владение с помощью «умного указателя», такого как unique_ptr (для исключительного владения) и shared_ptr (для совместного владения). Однако это менее элегантно и часто менее эффективно, чем возврат самого объекта, поэтому используйте умные указатели только в тех случаях, когда необходима семантика ссылок.
Альтернатива: Иногда более старый код нельзя изменить из-за требований совместимости ABI или нехватки ресурсов. В этом случае пометьте владеющие указатели с помощью owner из библиотеки поддержки руководящих принципов:
owner<X*> compute(args) // теперь ясно, что владение передаётся
{
owner<X*> res = new X{};
// ...
return res;
}
Это сообщает инструментам анализа, что res является владельцем. То есть его значение должно быть удалено с помощью delete или передано другому владельцу, как это делается здесь через return.
owner аналогично используется в реализации дескрипторов ресурсов.
Примечание
Предполагается, что каждый объект, переданный как сырой указатель (или итератор), принадлежит вызывающей стороне, так что его время жизни обрабатывается вызывающей стороной. С другой точки зрения: API с передачей владения относительно редки по сравнению с API с передачей указателей, поэтому по умолчанию — «без передачи владения».
Смотрите также: Передача аргументов, использование аргументов умных указателей и возврат по значению.
Контроль
- (Простой) Предупреждать о
deleteсырого указателя, который не являетсяowner<T>. Предлагать использование дескриптора ресурса стандартной библиотеки илиowner<T>. - (Простой) Предупреждать о невозможности либо
reset, либо явногоdeleteуказателяownerна каждом пути кода. - (Простой) Предупреждать, если возвращаемое значение
newили вызова функции с возвращаемым значениемownerприсваивается сырому указателю или не-ownerссылке.