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.
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_ptr
s 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. .
[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.
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.
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.
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;
}