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

Явное удаление shared_ptr

Простой вопрос здесь: разрешено ли явно удалять boost::shared_ptr самостоятельно? Если вы когда-нибудь?

Уточнение, я не имею в виду удаление указателя, хранящегося в shared_ptr. Я имел в виду собственно shared_ptr. Я знаю, что большинство людей предлагают не делать этого, поэтому мне просто интересно, нормально ли это делать.

4b9b3361

Ответ 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;
}