web-dev-qa-db-fra.com

Supprimer explicitement un shared_ptr

Question simple ici: êtes-vous autorisé à supprimer explicitement un boost::shared_ptr vous-même? Devriez-vous jamais?

En clarifiant, je ne veux pas dire supprimer le pointeur tenu par le shared_ptr. Je voulais dire le shared_ptr réel lui-même. Je sais que la plupart des gens suggèrent de ne pas le faire, alors je me demandais si on pouvait le faire explicitement.

18
garsh0p

Votre question n'est pas claire. Si vous avez alloué un shared_ptr de manière dynamique, vous êtes certainement autorisé à le remplacer par delete à tout moment. 

Mais si vous demandez si vous êtes autorisé à supprimer tout objet géré par le shared_ptr, la réponse est… cela dépend. Si shared_ptr::unique renvoie true, l'appel de shared_ptr::reset supprimera l'objet géré. Cependant, si shared_ptr::unique renvoie false, cela signifie qu'il existe plusieurs shared_ptrs qui partagent la propriété de cet objet. Dans ce cas, un appel à reset ne fera que décrémenter le compte de références de 1; la suppression effective de l'objet aura lieu lorsque le dernier shared_ptr gérant cet objet sera hors de portée ou sera lui-même reset.

MODIFIER:
Après votre modification, il semble que vous vous interrogiez sur la suppression d'un shared_ptr alloué dynamiquement. Quelque chose comme ça:

auto sp = new boost::shared_ptr<int>( new int(42) );

// do something with sp

delete sp;

Ceci est autorisé et fonctionnera comme prévu, bien que ce soit un cas d'utilisation inhabituel. Le seul inconvénient est que si, entre l'attribution et la suppression de sp, vous créez un autre shared_ptr qui partage la propriété de l'objet, la suppression de sp n'entraînera pas la suppression de l'objet, cela ne se produira que lorsque le compte de références de l'objet passera à 0. .

25
Praetorian

[Edit: vous pouvez delete un shared_ptr si et seulement si il a été créé avec new, comme pour tout autre type. Je ne vois pas pourquoi vous créeriez un shared_ptr avec new, mais rien ne vous en empêche.]

Eh bien, vous pourriez écrire delete ptr.get();.

Cela entraîne presque inévitablement un comportement indéfini lorsque les autres propriétaires partagés utilisent leur shared_ptr pour accéder à l'objet supprimé, ou que le dernier shared_ptr de l'objet est détruit et que l'objet est à nouveau supprimé.

Alors non, vous ne devriez pas.

Le but de shared_ptr est de gérer un objet qu'aucune "personne" n'a le droit ou la responsabilité de supprimer, car il pourrait y avoir d'autres propriétaires partageant la même propriété. Donc, vous ne devriez jamais le vouloir non plus.

5
Steve Jessop

Vous ne pouvez pas forcer son compte de référence à zéro, non.

Pensez à ce qui serait nécessaire pour que cela fonctionne. Vous devez vous rendre à chaque endroit où le shared_ptr est utilisé et le vider.

Si vous avez forcé le pointeur partagé à supprimer et que vous le définissez sur NULL, cela ressemblerait à un faible_ptr. Cependant, tous les emplacements dans le code utilisant cet objet shared_ptr ne sont pas prêts pour cela et s'attendent à contenir un pointeur valide. Ils n'ont aucune raison de rechercher NULL et ces bits de code planteraient.

2
Zan Lynx

Si vous voulez simuler le décrément, vous pouvez le faire manuellement sur le tas comme ceci:

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;
}

Ou sur la pile en utilisant std::shared_ptr::reset() comme ceci:

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;
} 

Mais ce n'est pas si utile.

1
wulfgarpro

La suppression explicite est pratique dans certains (très?) Rares cas.

En plus de la suppression explicite, vous DEVEZ parfois détruire explicitement un pointeur partagé lorsque vous le supprimez!

Les choses peuvent devenir étranges lors de l'interfaçage avec du code C, en passant un shared_ptr en tant que valeur opaque. 

Par exemple, j’ai le texte suivant pour passer des objets depuis et vers le langage de script Lua qui est écrit en 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 );
}

C'est donc un shared_ptr dans une mémoire malloc'd. L'inverse est ceci ... (configuration à appeler juste avant que Lua garbage ne récupère un objet et le "libère").

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;
}
0
Nigel Atkinson