J'utilise std::tr1::shared_ptr de manière intensive dans mon application. Cela inclut le passage d'objets en tant qu'arguments de fonction. Prenons l'exemple suivant :
class Dataset {...}
void f( shared_ptr< Dataset const > pds ) {...}
void g( shared_ptr< Dataset const > pds ) {...}
...
Bien que le passage d'un objet dataset via shared_ptr garantisse son existence dans f et g, les fonctions peuvent être appelées des millions de fois, ce qui entraîne la création et la destruction de nombreux objets shared_ptr. Voici un extrait du profil gprof plat d'une exécution récente :
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
9.74 295.39 35.12 2451177304 0.00 0.00 std::tr1::\_\_shared\_count::\_\_shared\_count(std::tr1::\_\_shared\_count const&)
8.03 324.34 28.95 2451252116 0.00 0.00 std::tr1::\_\_shared\_count::~\_\_shared\_count()
Ainsi, ~17% du temps d'exécution a été consacré au comptage de références avec des objets shared_ptr. Est-ce normal ?
Une grande partie de mon application est monofilière et je pensais réécrire certaines des fonctions en tant que
void f( const Dataset& ds ) {...}
et en remplaçant les appels
shared_ptr< Dataset > pds( new Dataset(...) );
f( pds );
avec
f( *pds );
à des endroits où je suis sûr que l'objet ne sera pas détruit alors que le flux du programme se trouve dans f(). Mais avant de me précipiter pour changer un tas de signatures de fonctions / appels, je voulais savoir quel était l'impact typique sur les performances du passage par shared_ptr. Il semble que shared_ptr ne devrait pas être utilisé pour les fonctions qui sont appelées très souvent.
Tout commentaire serait apprécié. Merci de votre lecture.
-Artem
Mise à jour : Après avoir modifié une poignée de fonctions pour accepter const Dataset&
le nouveau profil ressemble à ceci :
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
0.15 241.62 0.37 24981902 0.00 0.00 std::tr1::\_\_shared\_count::~\_\_shared\_count()
0.12 241.91 0.30 28342376 0.00 0.00 std::tr1::\_\_shared\_count::\_\_shared\_count(std::tr1::\_\_shared\_count const&)
Le fait que le nombre d'appels au destructeur soit inférieur au nombre d'appels à la copie du constructeur me laisse un peu perplexe, mais je suis globalement très satisfait de la diminution du temps d'exécution associé. Merci à tous pour leurs conseils.