2010-07-26 3 views
5

En C++, ff J'ai une classe qui a besoin de tenir un membre qui pourrait être allouée de façon dynamique et utilisé comme un pointeur, ou non, comme ceci:dynamiques vs membres de classe non dynamique

class A { 
    type a; 
}; 

ou

class A { 
    A(); 
    ~A(); 
    type* a; 
}; 

et dans le constructeur:

A::A { 
    a = new type(); 
} 

et destructor:

A::~A { 
    delete a; 
} 

Y a-t-il des avantages ou des inconvénients à l'un ou à l'autre, mis à part le facteur dynamique qui nécessite plus de code? Se comportent-ils différemment (à part le pointeur devant être déréférencé) ou sont-ils plus lents les uns que les autres? Lequel dois-je utiliser?

+2

Travaillez sur le bon code maintenable, puis, si nécessaire, travaillez sur les performances. –

+1

Votre deuxième 'A' est dangereux; vous devez définir le constructeur de la copie et 'operator =' aussi. Ne les possédez jamais, enveloppez-les de sorte que vous n'ayez pas besoin d'écrire * des * fonctions membres spéciales. – GManNickG

Répondre

0

Avec le pointeur vous avez plus de contrôle, mais aussi plus de responsabilités. Vous avez plus de contrôle dans le sens où vous pouvez décider plus précisément de la durée de vie de l'objet, tandis que sans le pointeur, la durée de vie est essentiellement égale à la durée de vie de l'objet conteneur. De plus, avec le pointeur, le membre pourrait être une instance d'une sous-classe du type pointeur. En ce qui concerne les performances, utiliser le pointeur signifie plus d'utilisation de la mémoire, plus de fragmentation de la mémoire, et le déréférencement prend du temps. Cependant, pour tout sauf le code le plus critique, rien de tout cela ne vaut vraiment la peine d'être inquiétant.

0

La principale différence est que le pointeur peut potentiellement pointer ailleurs.

modifier

réponse de Laurence est pas mal, mais il est un peu général. En particulier, l'allocation dynamique va être légèrement plus lente. Le déréférencement à travers le pointeur va également être très légèrement plus lent. Encore une fois, ce n'est pas beaucoup de perte de vitesse, et la flexibilité qu'il achète pourrait bien en valoir la peine.

0

La principale différence est que si vous n'utilisez pas de pointeur, la mémoire du membre interne sera allouée en tant que partie de la mémoire allouée à l'objet conteneur. Si vous utilisez new, vous obtiendrez de la mémoire en blocs séparés (vous semblez déjà avoir créé et détruit correctement l'objet référencé)

0

Vous devez comprendre les implications du constructeur de copie par défaut et des opérateurs d'affectation de copie lors de l'utilisation de pointeurs bruts . Le pointeur brut est copié dans les deux cas. En d'autres termes, vous finirez par avoir plusieurs objets (ou pointeurs bruts) pointant vers le même emplacement de mémoire. Par conséquent, votre destructeur écrit comme ci-dessus tentera de supprimer plusieurs fois la même mémoire.

5

Il existe plusieurs différences:

  1. doit être connue La taille de chaque membre lorsque vous définissez une classe. Cela signifie que vous devez inclure votre en-tête type, et vous ne pouvez pas utiliser une déclaration forward comme vous le feriez avec un membre pointeur (puisque la taille de tous les pointeurs est connue). Cela a des implications pour #include clutter et compiler les temps pour les grands projets.

  2. La mémoire de l'élément de données est partie de l'instance de classe enveloppante, de sorte qu'il sera allouée en même temps, au même endroit, comme tous les autres membres de la classe (que ce soit sur la pile ou le tas). Cela a des implications pour la localisation des données - tout ce qui se trouve au même endroit pourrait potentiellement conduire à une meilleure utilisation du cache, etc. L'allocation de pile sera probablement un peu plus rapide que l'allocation de tas. Déclarer trop d'instances d'objets énormes pourrait faire exploser votre pile plus rapidement. Le type de pointeur est plus délicat à gérer - puisqu'il n'est pas automatiquement alloué ou détruit avec la classe, vous devez vous assurer de le faire vous-même. Cela devient difficile avec plusieurs membres de pointeurs - si vous êtes tous dans le constructeur, et à mi-chemin il y a une exception, le destructeur n'est pas appelé et vous avez une fuite de mémoire. Il est préférable d'affecter des variables de pointeur à un conteneur "pointeur intelligent" (std::auto_ptr) immédiatement, de cette façon le nettoyage est géré automatiquement (et vous n'avez pas besoin de vous soucier de delete les dans le destructeur, vous évitant souvent d'écrire un du tout). En outre, chaque fois que vous manipulez des ressources manuellement, vous devez vous soucier des constructeurs de copie et des opérateurs d'affectation.

+0

L'ajout de conteneurs smart-pointer-includes (stl/boost) à votre projet augmente généralement votre temps de compilation beaucoup plus que l'inclusion de vos propres fichiers d'en-tête. Les allocations de pile, qui sont considérées comme bon marché, sont beaucoup plus rapides que les allocations de tas (qui sont considérées comme coûteuses). Pourquoi devriez-vous vous soucier des constructeurs de copie et des opérateurs d'affectation si vous manipulez les ressources manuellement? Assurez-vous de garder des pointeurs sur eux au lieu de les copier. (déclarez simplement copie/affectation comme privée et vous ne ferez jamais l'erreur de mal faire). – Simon

0

Si la variable membre doit vivre au-delà de la durée de vie de l'objet, ou si sa propriété doit être transférée à un autre objet, le membre doit être dynamique (tas) allouée à l'aide « nouvelle ». Si ce n'est pas le cas, alors c'est souvent le meilleur choix pour en faire un membre direct de la classe afin de simplifier le code et d'alléger le fardeau sur l'allocateur de mémoire. L'allocation de mémoire est chère.

Questions connexes