Quand utiliseriez-vous un std :: auto_ptr au lieu de boost :: shared_ptr?
-
22-07-2019 - |
Question
Nous avons plus ou moins utilisé boost :: shared_ptr
dans l'ensemble de notre code, mais nous avons encore quelques cas isolés d'utilisation de std :: auto_ptr
. , y compris les classes de singleton:
template < typename TYPE >
class SharedSingleton
{
public:
static TYPE& Instance()
{
if (_ptrInstance.get() == NULL)
_ptrInstance.reset(new TYPE);
return *_ptrInstance;
}
protected:
SharedSingleton() {};
private:
static std::auto_ptr < TYPE > _ptrInstance;
};
On m'a dit qu'il y avait une très bonne raison pour laquelle cela n'a pas été transformé en shared_ptr
, mais pour la vie de moi, je ne comprends pas pourquoi? Je sais que auto_ptr
finira par être marqué comme amorti dans le prochain standard. Je voudrais donc savoir ce que / comment je peux remplacer cette implémentation .
Par ailleurs, existe-t-il d'autres raisons pour lesquelles vous envisageriez d'utiliser un auto_ptr
au lieu d'un shared_ptr
? et voyez-vous des problèmes passer à shared_ptr à l'avenir?
Modifier:
- En réponse à " puis-je remplacer en toute sécurité
auto_ptr
parshared_ptr
dans le code ci-dessus, la réponse est oui, mais je vais prendre un petit coup en performance . - Lorsque
auto_ptr
est finalement marqué comme amorti et que nous passons àstd :: shared_ptr
, nous devons tester minutieusement notre code pour nous assurer de notre intégrité. par la sémantique de propriété différente.
La solution
auto_ptr
et shared_ptr
résolvent des problèmes totalement différents. L'un ne remplace pas l'autre.
auto_ptr
est une fine couche de pointeurs permettant de mettre en œuvre la Sémantique RAII . , afin que les ressources soient toujours libérées, même face à des exceptions. auto_ptr
n'effectue aucun comptage de références ou autre, il ne fait pas que plusieurs pointeurs pointent vers le même objet lors de la création de copies. En fait, c'est très différent. auto_ptr
est l'une des rares classes dans lesquelles l'opérateur d'affectation modifie l'objet source . Considérez cette fiche sans vergogne de la page wikipedia auto_ptr :
int *i = new int;
auto_ptr<int> x(i);
auto_ptr<int> y;
y = x;
cout << x.get() << endl; // Print NULL
cout << y.get() << endl; // Print non-NULL address i
Notez comment l'exécution
y = x;
modifie non seulement y mais aussi x.
Le modèle boost :: shared_ptr
facilite la gestion de plusieurs pointeurs sur le même objet. Cet objet n'est supprimé que lorsque la dernière référence à celui-ci est sortie de sa portée. Cette fonctionnalité n’est pas utile dans votre scénario qui implémente un Singleton . Dans votre scénario, il y a toujours soit 0 référence à 1 référence au seul objet de la classe, le cas échéant.
En substance, les objets auto_ptr
et les objets shared_ptr
ont une sémantique totalement différente (c'est pourquoi vous ne pouvez pas utiliser le premier dans des conteneurs, mais le faire avec le dernier convient très bien), et j'espère bien que vous aurez de bons tests pour détecter les régressions que vous avez introduites lors du portage de votre code. : -}
Autres conseils
D'autres ont répondu pourquoi ce code utilise un auto_ptr
au lieu d'un code_partagé
. Pour répondre à vos autres questions:
Quoi / comment je peux remplacer cette implémentation?
Utilisez boost :: scoped_ptr
ou unique_ptr
(disponible à la fois dans Boost et dans la nouvelle norme C ++). scoped_ptr
et unique_ptr
fournissent une propriété stricte (sans aucun temps de comptage de références) et évitent la sémantique surprenante de la suppression sur copie de auto_ptr
.
En outre, y a-t-il d'autres raisons pour lesquelles vous envisagez d'utiliser un auto_ptr
au lieu d'un shared_ptr
? Et voyez-vous des problèmes pour passer à shared_ptr
à l'avenir?
Personnellement, je n’utiliserais pas de auto_ptr
. Supprimer sur copie est tout simplement trop intuitif. Herb Sutter semble être d'accord . Passer à scoped_ptr
, unique_ptr
ou shared_ptr
ne devrait poser aucun problème. Plus précisément, shared_ptr
devrait remplacer immédiatement le client si vous ne vous souciez pas de la surcharge du comptage des références. scoped_ptr
est un remplacement immédiat si vous n'utilisez pas les fonctionnalités de transfert de propriété de auto_ptr
. Si vous utilisez le transfert de propriété, alors unique_ptr
est presque un remplacement immédiat, sauf que vous devez appeler explicitement move
pour transférer la propriété. Voir ici pour un exemple.
auto_ptr est le seul type de pointeur intelligent que j'utilise. Je l'utilise parce que je n'utilise pas Boost, et parce que je préfère généralement mes classes orientées métier / application à explicitement définir la sémantique et l'ordre de suppression, plutôt que de dépendre collections de pointeurs intelligents ou individuels.