J'ai eu récemment le bug de mémoire suivante, qui est facile à repérer, mais peut être plus difficile à détecter dans le code plus complexe:Pour obtenir le comptage des références, dois-je encombrer mes API avec shared_ptr?
class Foo : public IFoo {
const Bar& bar_;
public:
Foo(const Bar& bar) : bar_(bar) {
}
void test() {
// access bar_ here
}
};
int baz() {
IFoo* foo = NULL;
if(whatever) {
Bar bar;
foo = new Foo(bar);
}
else {
// create other foo's
}
foo->test(); // segmentation fault
}
Le bug est que Bar
immédiatement est hors de portée, est détruit puis utilisé dans foo->test()
. Une solution consiste à créer Bar
sur le tas, en utilisant Bar* bar = new Bar()
. Cependant, je n'aime pas faire cela parce que je devrais garder le pointeur Bar* bar
au niveau supérieur pour que je puisse y accéder et delete
à la fin, même si Bar
est quelque chose qui est spécifique à ce bloc de code particulier if(whatever){}
.
Une autre solution est boost::shared_ptr<Bar>
, mais je ne peux pas écrire ceci:
if(whatever) {
boost::shared_ptr<Bar> bar(new Bar());
foo = new Foo(*bar);
}
depuis le shared_ptr
est hors de portée immédiatement, aussi, détruire l'objet contenu.
Donc en bref, pour se débarrasser de ce problème, je dois utiliser shared_ptr
partout, en Foo
comme variable membre, dans le constructeur de Foo
, etc. Pour éliminer ces problèmes en général, toutes mes API etc doivent utiliser shared_ptr
, ce qui est un peu moche. Mais, est-ce la bonne chose à faire? Jusqu'à présent, je l'ai utilisé parfois pour créer des objets comptés par référence, mais j'ai gardé mes API propres de shared_ptr
. Comment gérez-vous ce problème que, une fois que vous utilisez shared_ptr
vous devez l'utiliser partout?
(De plus, si vous utilisez ces pointeurs de référence compté, vous devez commencer à se soucier si vous voulez vraiment shared_ptr
ou plutôt weak_ptr
etc.)
Et, qu'est-ce que j'utiliser comme un équivalent à Foo(const Bar& bar)
? Foo(const shared_ptr<const Bar> bar)
? Une autre option, bien sûr, est d'ajouter vous-même le comptage des références à l'intérieur du Bar
et d'autres objets, en utilisant pimpl
et vos propres compteurs, mais cela devient en général trop fastidieux.
Merci! J'aime la solution typedef. Et je ne savais pas que 'weak_ptr' serait vu comme une référence? Intéressant. (A propos de l'allocation de tas, j'ai discuté de cela dans ma question :-) – Frank
@dehmann, weak_ptr comme référence est ma propre convention, mais au moins pour moi cela a du sens - weak_ptr ne possède pas d'objet, juste des références à celui-ci. –
Je viens de "typedef" "boost :: shared_ptr" globalement dans "sp" (via l'héritage, car les typedefs ne supportent pas le template). beaucoup moins de travail –