6
votes

Boost :: make_shared n'appelle pas l'opérateur (placement) Nouveau?

J'utilise boost :: make_shared Pour la première fois pour créer des objets pointés par des pointeurs partagés. Principalement parce que notre code était trop lent et que l'allocation unique a vraiment contribué à améliorer les performances.

Après avoir fixé des fuites de mémoire "The Hard Manual Way", j'ai décidé de mettre en place un détecteur de fuites de mémoire simple en remplaçant de nouveaux opérateurs pour toutes les classes pertinentes pour Compter quels objets sont toujours en vie à des points spécifiques de notre application. J'ai déjà mis en œuvre cela plusieurs fois avant et j'ai été surpris de trouver mon code ne détecte plus aucun objet.

J'ai pensé que tout ce que je devais faire est de remplacer "le placement nouveau" au lieu de l'opérateur "normal", car des éléments suivants de la documentation du site Web de Boost pour make_shared:

"Effets: alloue la mémoire appropriée pour un objet de type T et construit un objet dans celui-ci via la nouvelle expression nouvelle (PV) T () ou neuf (PV) T (STD :: AVANT (args) ...) . allO4_shared utilise une copie de A pour allouer la mémoire. Si une exception est lancée, n'a pas effet. "

Mon placement nouveau n'est également pas appelé cependant. J'ai écrit un petit programme de test pour reproduire le comportement: xxx

qui rend la sortie suivante: xxx

J'étais S'attendre à ce que "test non-jetant non jetant nouveau" sur la 3ème ligne de sortie. Que pensez-vous que le comportement devrait être? Êtes-vous d'accord pour dire que, selon la documentation de make_shared, il devrait appeler le nouvel opérateur de placement de ma classe de test? Ou ai-je mal compris?

Je pourrais copier la mise en œuvre localement et ajouter un appel au nouvel opérateur de placement bien sûr. Mais cela serait-ce approprié ou violerait-il la sémantique envisagée du placement nouveau?

Merci d'avance pour votre temps et votre aide.


1 commentaires

En regardant Boost's , il utilise le nouvel opérateur de placement global :: Nouveau (PV) T (). C'est pourquoi votre placement de niveau de classe n'est pas appelé ... en supprimez le qualificatif global '::' Avant nouveau, le make_shared appelle en fait votre ancien opérateur de placement de niveau de classe.


3 Réponses :




3
votes

Votre opérateur Nouveau implémenté pour votre type particulier ne sera utilisé que sur les expressions sur lesquelles les éléments de votre type sont alloués de manière dynamique avec neuf , telle que test * p = nouveau test; . Maintenant, make_shared n'est pas allouer de manière dynamique un objet de votre type, mais plutôt un tampon qui contient suffisamment d'informations pour le compte partagé (qui inclut le compteur, le Deleter et quelques bits et morceaux supplémentaires) et votre objet.

Il utilise ensuite placement-nouveau pour appeler le constructeur de votre objet. Notez que le placement nouveau dans ce cas ne correspond pas à la mémoire, ce n'est que la syntaxe amusante en C ++ pour appeler le constructeur sur un bloc de mémoire déjà allouée. Cela pourrait en réalité être la source de confusion, comme l'expression nouvelle , votre Opérateur neuf et placement-nouveau sont trois concepts différents qui se produisent un nom.


1 commentaires

Malgré cela, il est toujours possible de fournir une surcharge par classe, même pour le placement nouveau. Peu de temps peut-être, mais encore une fois, quelle partie de C ++ n'est pas insolite :-) Le point principal à ramener est que std :: allocator n'utilise aucun par -Class Fonctions d'allocation, mais seulement le global :: nouveau .