Отключить указатель от shared_ptr?

Возможный дубликат:
Как освободить указатель от boost::shared_ptr?

Функция моего интерфейса возвращает указатель на объект. Пользователь должен стать владельцем этого объекта. Я не хочу возвращать Boost.shared_ptr, потому что я не хочу заставлять клиентов использовать boost. Однако внутренне я хотел бы сохранить указатель в shared_ptr для предотвращения утечек памяти в случае исключений и т. Д. Похоже, что нет способа отсоединить указатель от общего указателя. Есть идеи здесь?

5 ответов

Решение

То, что вы ищете, это release функция; shared_ptr не имеет функции разблокировки. В соответствии с руководством Boost:

В. Почему shared_ptr не предоставляет функцию release()?

A. shared_ptr не может передать право владения, если он не уникален (), потому что другая копия все равно уничтожит объект.

Рассматривать:

shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2

int * p = a.release();

// Who owns p now? b will still call delete on it in its destructor.

Кроме того, указатель, возвращаемый функцией release(), будет трудно надежно освободить, так как источник shared_ptr мог быть создан с помощью пользовательского средства удаления.

Вы можете рассмотреть два варианта:

  • Вы могли бы использовать std::tr1::shared_ptr, что потребовало бы от ваших пользователей использования реализации библиотеки C++, поддерживающей TR1, или использования Boost; по крайней мере, это даст им возможность выбора между ними.
  • Вы могли бы реализовать свой собственный boost::shared_ptr-подобный разделяемый указатель и использовать его на внешних интерфейсах.

Вы также можете посмотреть обсуждение этого вопроса об использовании boost::shared_ptr в публичном интерфейсе библиотеки.

Всегда есть способ:-)

Действительно, есть причина, по которой они не предоставляют метод release(), но его невозможно создать. Сделайте свой собственный удалитель. Что-то на линии (на самом деле не скомпилировал код, но это общее понятие):

template <typename T>
class release_deleter{
public:
  release_deleter() : released_(new some_atomic_bool(false)){}
  void release() {released_->set(true);}
  void operator()(T* ptr){if(!released_->get()) delete ptr;}
private:
  shared_ptr<some_atomic_bool> released_;
}

..

shared_ptr<some_type> ptr(new some_type, release_deleter<some_type>());

..

release_deleter<some_type>* deleter = get_deleter<release_deleter<some_type>>(ptr);
deleter->release();
some_type* released_ptr = ptr.get();

Пользователь должен стать владельцем этого объекта. Я не хочу возвращать Boost.shared_ptr,

shared_ptr выражает общее владение, и вы хотите, чтобы ваш интерфейс выражал передачу права собственности. std::auto_ptr Таким образом, будет более применимым здесь.

Однако внутренне я хотел бы сохранить указатель в shared_ptr, чтобы предотвратить утечки памяти в случае исключений

Снова, shared_ptr не может быть лучшим инструментом для этой работы. Чтобы предотвратить утечки в случае исключений, scoped_ptr или же auto_ptr будет лучше подходит.

Использовать shared_ptr к scoped_ptr на ресурс (shared_ptr<scoped_ptr<Resource>>). Таким образом, вы получаете shared_ptrподсчет ссылок, который автоматически уничтожит ресурс, если и только если он все еще подключен к scoped_ptr, Но вы можете отсоединить scoped_ptr когда вы будете готовы передать права собственности.

Поскольку Джеймс хорошо рассказал, вы не можете отсоединить общий указатель.

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

Если вы беспокоитесь об удивительной семантике std::auto_ptr, вы могли бы держать его внутри boost::scoped_ptrи отсоедините его в том месте, где вы его раздали, предоставив клиенту возможность вручную удалить его или сохранить в собственном интеллектуальном указателе.

Если у вас есть несколько владельцев на вашей стороне, вы можете использовать навязчивый счет. Внутренне вы можете использовать boost::intrusive__ptr, но передайте необработанный указатель на интерфейс. Затем клиент может либо вручную работать с подсчетом ссылок, либо сохранить его в boost::intrusive_ptr сами (но вы не заставляете их зависеть от этого)

Другие вопросы по тегам