Вопрос

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

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

Это было полезно?

Решение

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

К.Почему в Shared_ptr нет функции Release()?

А.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 сами (но вы не заставляете их зависеть от этого)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top