Отсоединить указатель от Shared_ptr?[дубликат]
-
11-09-2019 - |
Вопрос
Возможный дубликат:
Как освободить указатель из 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
сами (но вы не заставляете их зависеть от этого)