2009-03-10 6 views
9

J'ai un projet dont j'aimerais utiliser davantage les pointeurs intelligents. Dans l'ensemble, j'ai réussi à atteindre cet objectif. Cependant, j'ai rencontré une chose dont je ne suis pas sûr de savoir ce que sont les «meilleures pratiques».renvoyant un 'pointeur' qui doit être tenu par un pointeur intelligent

Fondamentalement, je voudrais retourner un "pointeur" d'une fonction, mais exige que l'utilisateur le maintient dans un pointeur intelligent. Non seulement cela, je ne veux pas mandater un pointeur intelligent particulier (partagé vs portée). Le problème est surtout qu'il ne semble pas y avoir une bonne façon de mettre à niveau un scoped_ptr vers un shared_ptr (ce serait la solution idéale je pense). Je comprends pourquoi ils ne l'ont pas fait, car cela permettrait le transfert de propriété, ce qui peut conduire à des problèmes comme ceux que connaît le std::auto_ptr.

Cependant, le transfert de propriété semble être une bonne idée pour ce cas. Donc, mon idée est comme ceci:

// contrived example of factory pattern 
std::auto_ptr<A> func() { return std::auto_ptr<A>(new A); } 

Cela fonctionne « ok » puisque les deux scoped_ptr et shared_ptr ont des constructeurs qui prennent la propriété d'un std::auto_ptr. Donc, ma question est la suivante: est-ce une bonne pratique? Y a-t-il une meilleure solution? La seule alternative que j'ai été en mesure de trouver utilise un modèle de modèle comme la valeur de retour comme ceci:

// similar to above example 
template <template <typename> class P> 
P<A> func() { return P<A>(new A); } 

qui en fait pourrait bien fonctionner sauf que je pense qu'il aurait besoin d'un peu de travail pour l'obtenir à travailler avec un scoped_ptr aussi.

Pensées?

Répondre

11

L'utilisation std::auto_ptr est la bonne pratique, en fait such example a été suggéré par Bjarne Stroustrup.

La sémantique de déplacement de auto_ptr vous donne les bons outils pour y faire face.

Par exemple:

auto_ptr<Foo> make_foo() 
{ 
    return auto_ptr<Foo>(new Foo); 
} 

Foo *raw_pointer=make_foo().release(); 
shared_ptr<Foo> shared_pointer=make_foo(); 
auto_ptr<Foo> auto_pointer=make_foo(); 

Si vous retournez shared_ptr vous ne pouvez pas fallback à pointeur normal, avec auto_ptr vous pouvez. Vous pouvez toujours mettre à jour auto_ptr à partager mais pas dans d'autres directions.

Un autre point important, shared_ptr utilise le comptage de référence atomique, c'est beaucoup plus lent que le travail simple et pourtant entièrement efficace que fait .

P.S .: scoped_ptr est juste la version de auto_ptr pour les pauvres - il est non-copyable et ne pas constator par défaut. Il est plus comme "moins confus" version de auto_ptr, par rapport à shared_ptr il n'est pas en tr1. En général, il n'y avait pas beaucoup d'avantages de l'utilisation scoped_ptr sur auto_ptr

+0

shared_ptr dans la construction à un seul thread n'utilise pas le comptage atomique des références. –

+0

Vous avez raison, mais par défaut, boost est construit en version multithread. – Artyom

+2

L'avantage d'utiliser scoped_ptr sur auto_ptr est lorsque vous voulez indiquer clairement que vous n'êtes pas censé copier le pointeur. Vous ne pouvez tout simplement pas avec scoped_ptr. Il s'agit de transmettre vos intentions, tout comme votre exemple avec auto_ptr et le transfert de propriété. –

3

Si vous construisez une usine c'est ok que vous renvoyez simplement un pointeur. Et l'utilisateur de votre usine peut prendre sa propre décision comment et où mettre ce pointeur.
Si vous devez appliquer le pointeur intelligent, vous devez limiter le choix car vous ne voulez pas qu'ils utilisent de "mauvais".
Donc boost :: shared_ptr. Mais mieux vaut le typedef alors à MyClassPtr ou MyClass :: ptr.
Pourtant, les usines sont comme "neuf". Quand je veux, je mets le résultat de new à l'intérieur de std :: auto_ptr. Mais je ne veux pas être forcé d'appeler "release" toutes les fois où je ne veux pas de pointeur intelligent.

+0

vrai, mais je voudrais imposer l'utilisation d'un pointeur intelligent si possible. –

+0

Je suis d'accord, nous sommes tous des adultes ici. Renvoyer un pointeur nu et laisser l'utilisateur du code décider comment mieux attraper la valeur de retour. Je crois que le constructeur de shared_ptr d'un auto_ptr s'en va (auto_ptr va être déprécié). –

+0

lorsque auto_ptr est déprimé en C++ 0x, unique_ptr le remplacera. Je passerais à retourner unique_ptr alors. – Aaron

1

Avec 11 C++, vous devriez être en mesure d'utiliser std::unique_ptr comme les autres types de pointeurs intelligents ont des constructeurs qui prennent std::unique_ptr. Si vous maintenez une liste interne de ces ressources, vous voudrez probablement utiliser std::shared_ptr.

Questions connexes