Bonne façon de réaffecter les pointeurs en c++
EDIT: je sais que dans ce cas, si il s'agissait d'une classe réelle, je serais mieux de ne pas mettre la chaîne sur le tas. Cependant, c'est juste un exemple de code pour m'assurer de comprendre la théorie. Le code va être d'un rouge noir de l'arbre, avec tous les nœuds stockées sur le tas.
Je veux m'assurer d'avoir ces idées de base correcte avant de passer (je viens d'une Java/Python à l'arrière-plan). J'ai été chercher sur le net, mais n'ai pas trouvé de réponse concrète à cette question.
Lorsque vous réaffectez un pointeur vers un nouvel objet, vous devez appeler delete sur l'ancien objet en premier pour éviter une fuite de mémoire? Mon intuition me dit que oui, mais je veux une réponse concrète avant de passer.
Par exemple, disons que vous avez eu une classe qui stockée un pointeur vers une chaîne
class MyClass
{
private:
std::string *str;
public:
MyClass (const std::string &_str)
{
str=new std::string(_str);
}
void ChangeString(const std::string &_str)
{
//I am wondering if this is correct?
delete str;
str = new std::string(_str)
/*
* or could you simply do it like:
* str = _str;
*/
}
....
Dans le ChangeString méthode, qui serait correct?
Je pense que je suis accroché sur si vous n'avez pas utiliser le mot clé new pour la deuxième façon, il sera toujours compiler et exécuter comme prévu. Est-ce que cela écraser les données, que ce pointeur pointe vers? Ou faut-il faire autre chose?
Tout conseil serait grandement appricated 😀
- Il est plus que probable que vous ne devriez pas être affecter une chaîne de caractères avec
new
en premier lieu. Avez-vous une raison particulière pour que? - Lire la modifier en haut de la page
- Une plus de chose naturelle à faire ici, serait toujours:
*str = _str;
(pas besoin de jeter une chaîne et d'en créer un autre, si vous voulez juste pour affecter le contenu) - C'est à peu près ce que ma question sur les centres de. Si je l'ai fait de cette façon, je l'aurais je une fuite de mémoire? D'après les commentaires ci-dessous, il sonne comme je le ferais.
- Si vous voulez ared-l'arbre noir, quel est le problème avec std::map?
- le but entier de la rouge noir de l'arbre est juste pour me faire intruduced de la langue et de la syntaxe de/etc. Chaque fois que je apprendre une nouvelle langue, je commence par la construction d'un rouge noir de l'arbre afin de m'assurer de comprendre les principes de base (c'est à peu près mon "hello world")
- Naturellement, vous n'obtiendrez pas une fuite de mémoire avec
*str = _str;
(parce questd::string
lui-même n'a pas de fuite). Notez que c'est de travailler avec des objets existants, pas d'adresses. - @Neil: Tout programmeur C++ doit être capable de gérer la mémoire manuellement et la mise en œuvre d'un RAII classe avec builtin les constructions de langage, donc il n'y a rien de mal à faire ces choses comme un exercice. - Merci, c'est exactement ce que je cherchais (n'était pas sûr si elle l'emporterait sur l'objet le pointeur souligné, ou en créer un nouveau, quelque part, entraînant une fuite de mémoire). C'est maintenant à moi de comprendre que "*pObject = DifferentObject' faudra juste remplacer l'ancien objet pObject points et à ne pas entraîner une fuite de mémoire. Merci
- Il n'est pas exact de dire que
*pObject = DifferentObject
écrasera l'ancien objet. Il demande de l'opérateur d'affectation de pObject qui sera probablement copier le ème de l'information à partir de DifferentObject. (Dans le cas de std::string, oui, pObject finira contenant les mêmes caractères que DifferentObject fait.) - Simplement être en mesure de pirater un ensemble rouge-noir l'arbre, qui compile et semble ne pas vraiment vous apprendre quelque chose d'utile sur le C++. En C++, satisfaisant le compilateur est le moindre de vos problèmes. L'écriture d'un rouge-noir arbre comme un exercice d'apprentissage est une bonne idée, mais pour réellement apprendre quelque chose, vous devrez vous assurez que c'est 1) corriger, et 2) raisonnablement idiomatiques C++. Le premier est difficile à vérifier sur votre propre, et la deuxième est impossible. Qu'allez-vous faire pour vous assurer que vous apprendre quelque chose de cet exercice?
Vous devez vous connecter pour publier un commentaire.
Si vous devez libérer de l'ancienne instance et en créer un autre, vous devez d'abord assurez-vous que la création du nouvel objet réussit:
Si vous appelez supprimer la première, puis la création d'une nouvelle déclenche une exception, alors l'instance de classe serez à gauche avec une balançant pointeur. E. g, votre destructeur pourrait essayer de supprimer le pointeur de nouveau (comportement indéfini).
Vous pourriez aussi éviter que par le réglage de pointeur NULL dans un entre-deux, mais la façon décrite ci-dessus est encore mieux: si la réinitialisation échoue, l'objet garde sa valeur d'origine.
Quant à la question dans le commentaire de code.
Ce serait la bonne chose à faire. Il est normal que la chaîne de cession.
Ce serait affectation de pointeurs et complètement faux. Vous serait fuite de la chaîne d'instance précédemment souligné par
str
. Pire encore, il est très probable que la chaîne de caractères passée à la fonction n'est pas alloué avecnew
en premier lieu (vous ne devriez pas être un mélange des pointeurs vers attribuées de manière dynamique et automatique des objets). En outre, vous pouvez stocker l'adresse d'une chaîne d'objets dont la durée de vie se termine avec l'appel de la fonction (si la const de référence est lié à une temporaire).Pourquoi pensez-vous que vous avez besoin de stocker un pointeur vers une chaîne de caractères dans votre classe? Les pointeurs C++ collections comme les string sont en fait très rarement nécessaire. Votre classe doit presque certainement ressembler à:
Juste pointer ici, mais
ne serait pas compiler (que vous essayez d'attribuer _str, qui est la valeur d'une chaîne de caractères passée par référence, à la str, qui est l'adresse d'une chaîne). Si vous vouliez faire, vous écrivez :
(et vous auriez à changer _str ou str, de sorte que le constnest matches).
Mais alors, que votre intuition vous dit, vous auriez fui la mémoire de la chaã objet a été déjà souligné par str.
Comme indiqué précédemment, lorsque vous ajoutez une variable à une classe en C++, vous devez penser si la variable est la propriété de l'objet, ou par quelque chose d'autre.
Si elle est détenue par l'objet, que vous êtes probablement mieux avec les stocker en tant que valeur, et la copie de trucs autour (mais alors vous devez vous assurer que les copies ne se produisent pas dans votre dos).
Il est n'est pas la propriété, alors vous pouvez le stocker en tant que pointeur, et vous n'avez pas nécessairement besoin de faire des copies tout le temps.
D'autres personnes vous expliquera cela mieux que moi, parce que je ne suis pas vraiment à l'aise avec elle.
Ce que j'ai fini par faire un lot est de l'écriture de code comme ceci :
Qui est, si un objet dépend de quelque chose dans le "Java" /" Cio " du sens (l'existence d'objets d'ailleurs, vous n'êtes pas créer, et vous veut seulement appel de méthode), je voudrais stocker la dépendance comme une référence, à l'aide de dep_xxxx.
Si je crée l'objet, je voudrais utiliser un pointeur, avec un p_ préfixe.
C'est juste pour rendre le code plus "immédiate". Pas sûr que ça aide.
Juste mon 2c.
Bonne chance avec la mémoire intégrée, vous avez raison, c' est la partie la plus délicate à venir de Java ; ne pas écrire de code jusqu'à ce que vous êtes à l'aise, ou vous allez passer des heures à chasser segaults.
En espérant que cela aide !
La règle générale en C++, c'est que pour chaque objet créé avec la "nouvelle" il doit y avoir un "supprimer". Veillant à ce que cela se passe toujours dans la partie la plus difficile 😉 Moderne programmeurs C++ éviter de créer de la mémoire sur le tas (c'est à dire avec les "nouvelles") comme de la peste et de l'utilisation de la pile des objets à la place. Vraiment prendre en compte si vous devez être à l'aide de "nouveau" dans votre code. Il est rarement nécessaire.
Si vous êtes en provenance d'un arrière-plan avec les ordures ménagères collectées langues et trouvez-vous vraiment besoin d'utiliser la mémoire du tas, je suggère d'utiliser le boost partagé des pointeurs. Vous utiliser comme ceci:
myPointer a à peu près le même langage sémantique comme un pointeur normal, mais shared_ptr utilise le comptage de référence pour déterminer quand la suppression de l'objet, c'est le référencement. C'est essentiellement le faire vous-même la collecte des ordures. Les docs sont ici: http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm
Je vais juste écrire une classe pour vous.
Pour les classes qui disposent de ressources comme cela, le constructeur de copie, opérateur d'affectation, et le destructeur sont tous nécessaires. La partie la plus délicate du constructeur de copie et l'opérateur d'affectation est que vous devez supprimer chaque
Foo
précisément la fois. Si le constructeur de copie d'initialiseur avait dit:foo(a.foo)
, notamment alors queFoo
serait supprimé une fois l'objet en cours d'initialisation a été détruit et une fois lorsque l'objet est initialisé à partir d' (a
) a été détruit.La classe, la façon dont je l'ai écrit, doit être documentée de la prise de possession de la
Foo
pointeur c'est passé, parce queFoo * f = new Foo(); A a(f); delete f;
entraîne également la double suppression.Une autre façon de le faire serait d'utiliser des pointeurs intelligents de Boost (qui ont été au cœur de la prochaine norme de pointeurs intelligents) et ont
boost::shared_ptr<Foo> foo;
au lieu deFoo * f;
dans la définition de classe. Dans ce cas, le constructeur de copie doit êtreA(const A &a):foo(a.foo) {}
, depuis le pointeur intelligent prendra soin de la suppression de laFoo
lorsque toutes les copies du pointeur partagé le montrant du doigt, sont détruits. (Il y a des problèmes, vous pouvez obtenir dans ici, trop, surtout si vous mélangezshared_ptr<>
s avec toute autre forme de pointeur, mais si vous vous en tenez àshared_ptr<>
à travers vous devriez être OK.)Note: j'ai écris ce, sans procéder à un compilateur. Je vise la précision et le bon style (telles que l'utilisation des initialiseurs dans les constructeurs). Si quelqu'un trouve un problème, s'il vous plaît commentaire.
foo = foo_
dans setFoo ne fonctionne pas.foo
étaitFoo *
.Trois commentaires:
Vous avez besoin d'un destructeur ainsi.
Que vous n'avez vraiment pas besoin d'utiliser de segment de mémoire allouée dans ce cas. Vous pouvez effectuer les opérations suivantes:
Vous ne pouvez pas faire le commentaire sur version. Ce serait une fuite de mémoire. Java prend en charge que parce qu'il a la collecte des ordures. C++ ne possède pas cette fonctionnalité.
Oui. Si c'est un pointeur brut, vous devez supprimer l'ancien premier objet.
Il y a de pointeur intelligent de classes qui vont le faire pour vous lorsque vous attribuer une nouvelle valeur.