Явное удаление shared_ptr
Простой вопрос здесь: разрешено ли явно удалять boost::shared_ptr
самостоятельно? Если вы когда-нибудь?
Уточнение, я не имею в виду удаление указателя, хранящегося в shared_ptr
. Я имел в виду собственно shared_ptr
. Я знаю, что большинство людей предлагают не делать этого, поэтому мне просто интересно, нормально ли это делать.
Ответы
Ответ 1
Ваш вопрос непонятен. Если вы присвоили shared_ptr
динамически, то вам, безусловно, разрешено delete
его всякий раз, когда вы хотите.
Но если вы спрашиваете, разрешено ли вам удалять любой объект, управляемый с помощью shared_ptr
, тогда ответ будет... это зависит. Если shared_ptr::unique
возвращает true, то вызов shared_ptr::reset
удалит управляемый объект. Однако, если shared_ptr::unique
возвращает false, это означает, что существует более одного shared_ptr
совместного использования этого объекта. В этом случае вызов reset
приведет только к тому, что счетчик ссылок будет уменьшен на 1, фактическое удаление объекта произойдет, когда последний shared_ptr
управляет этим объектом либо выходит из области видимости, либо сам является reset
.
EDIT:
После редактирования вы спрашиваете об удалении динамически распределенного shared_ptr
. Что-то вроде этого:
auto sp = new boost::shared_ptr<int>( new int(42) );
// do something with sp
delete sp;
Это разрешено и будет работать должным образом, хотя это будет необычный случай использования. Единственное предостережение заключается в том, что если между распределением и удалением sp
вы создаете еще один shared_ptr
, который разделяет право собственности на объект, удаление sp
не приведет к удалению объекта, что произойдет, только когда счетчик ссылок для объекта идет 0.
Ответ 2
[Изменить: вы можете delete
a shared_ptr
тогда и только тогда, когда он был создан с помощью new
, как и любой другой тип. Я не могу понять, почему вы создали shared_ptr
с new
, но вам ничего не мешает.]
Ну, вы могли бы написать delete ptr.get();
.
Это приводит почти неизбежно к поведению undefined, когда другие владельцы используют свой shared_ptr
для доступа к удаленному объекту или к последнему shared_ptr
к объекту уничтожается, и объект снова удаляется.
Нет, не стоит.
Цель shared_ptr
состоит в том, чтобы управлять объектом, который ни один "человек" не имеет права или ответственности для удаления, поскольку другие могут делиться правами собственности. Поэтому вы тоже не должны этого хотеть.
Ответ 3
Вы не можете заставить свой счетчик ссылок равным нулю, нет.
Подумайте, что потребуется для этого. Вам нужно будет пойти в каждое место, где используется shared_ptr, и очистить его.
Если вы вынудили общий указатель удалить и установить его в NULL, он будет похож на weak_ptr. Тем не менее, все эти места в коде с использованием этого shared_ptr не готовы к этому и ожидают иметь действительный указатель. У них нет причин проверять NULL, и поэтому эти биты кода будут разбиваться.
Ответ 4
Если вы хотите симулировать декремент счета, вы можете сделать это вручную в куче, например:
int main(void) {
std::shared_ptr<std::string>* sp = new std::shared_ptr<std::string>(std::make_shared<std::string>(std::string("test")));
std::shared_ptr<std::string>* sp2 = new std::shared_ptr<std::string>(*sp);
delete sp;
std::cout << *(*sp2) << std::endl; // test
return 0;
}
Или в стеке с помощью std::shared_ptr::reset()
следующим образом:
int main(void) {
std::shared_ptr<std::string> p = std::make_shared<std::string>(std::string("test"));
std::shared_ptr<std::string> p2 = p;
p.reset();
std::cout << *p2 << std::endl; // test
return 0;
}
Но это не так полезно.
Ответ 5
В некоторых (очень?) редких случаях полезно использовать удаление.
Помимо явного удаления, иногда вы должны явно уничтожить общий указатель, когда вы его удаляете!
Вещи могут стать странными при взаимодействии с кодом C, передав shared_ptr как непрозрачное значение.
Например, у меня есть следующее для передачи объектов на и с языка сценариев Lua, который написан на C. (www.lua.org)
static void push( lua_State *L, std::shared_ptr<T> sp )
{
if( sp == nullptr ) {
lua_pushnil( L );
return;
}
// This is basically malloc from C++ point of view.
void *ud = lua_newuserdata( L, sizeof(std::shared_ptr<T>));
// Copy constructor, bumps ref count.
new(ud) std::shared_ptr<T>( sp );
luaL_setmetatable( L, B::class_name );
}
Итак, это shared_ptr в некоторой памяти malloc'd. Реверс - это... (настройка должна быть вызвана непосредственно перед тем, как мусор Lua собирает объект и "освобождает его".
static int destroy( lua_State *L )
{
// Grab opaque pointer
void* ud = luaL_checkudata( L, 1, B::class_name );
std::shared_ptr<T> *sp = static_cast<std::shared_ptr<T>*>(ud);
// Explicitly called, as this was 'placement new'd
// Decrements the ref count
sp->~shared_ptr();
return 0;
}