Передача необработанного указателя в общедоступном API, который имеет семантику владения, должна выполняться очень редко и только тогда, когда это абсолютно необходимо. Например. взаимодействие с кодом, интерфейс которого вы не можете изменить.
Передача необработанного указателя в частном API, например у членов одного класса проблем нет.
Рассмотрим эти три функции:
void f(A* a);
void g(std::unique_ptr<A> a);
void h(std::shared_ptr<A> a);
Семантика владения f
не ясна. Если вы являетесь клиентом f
, вам необходимо прочитать документацию, чтобы выяснить, собирается ли f
освободить a
, или игнорировать проблемы владения для a
.
Семантика владения g
ясна. Когда вы звоните g
, вы передаете право владения a
g
и больше не несете за него ответственность. g
либо освободит a
, либо передаст право собственности на этот ресурс в другое место.
Семантика владения h
ясна. Когда вы звоните h
, вы и h
становитесь совладельцами a
. Последний выключает свет.
void q(boost::intrusive_ptr<A> a);
q
имеет ту же семантику владения, что и h
. Основное отличие состоит в том, что должны существовать следующие свободные функции:
intrusive_ptr_add_ref(A*);
intrusive_ptr_release(A*);
Если вы являетесь автором f
и вызываете эти функции на a
, вам следует документально подтвердить это. Ваши клиенты не обязательно будут знать, что вы есть. И если вы клиент f
, у вас нет возможности узнать, вызовет ли f
эти функции, если вы не прочитаете его документацию.
Если вы являетесь автором f
и намереваетесь вызывать функции intrusive_ptr_*
, вы можете сделать это явным образом в своем интерфейсе, кодируя вместо него q
.
Но, как правило, нет веской причины навязывать автору A
написание функций intrusive_ptr_*
. И вы можете получить ту же семантику владения, что и q
, написав вместо этого h
, не налагая каких-либо дополнительных требований на A
.
Нагрузка на память
Если вы создаете shared_ptr
с помощью:
shared_ptr<A> p = make_shared(arguments-to-construct-an-A);
тогда ваш shared_ptr
будет иметь те же накладные расходы памяти, что и intrusive_ptr
. Реализация выделит A и refcount в том же распределении памяти. Ваши клиенты не должны знать или заботиться о том, что ваш shared_ptr
был построен так эффективно.