Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

Q. Почему 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, что потребует от ваших пользователей использования реализации библиотеки С++, поддерживающей TR1, или для использования Boost; по крайней мере, это даст им выбор между ними.
  • Вы можете реализовать свой собственный boost::shared_ptr -подобный общий указатель и использовать его на внешних интерфейсах.

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

Ответ 2

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

Существует действительно причина, по которой они не предоставляют метод 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();

Ответ 3

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

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

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

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

Ответ 4

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

Ответ 5

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

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

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

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