Instanciation De L'Objet C++

je suis un programmeur C essayant de comprendre C++. De nombreux tutoriels montrent l'instanciation d'un objet à l'aide d'un extrait tel que:

Dog* sparky = new Dog();

ce qui implique que plus tard vous ferez:

delete sparky;

ce qui a du sens. Maintenant, dans le cas où l'allocation de mémoire dynamique est inutile, y a-t-il une raison d'utiliser ce qui précède à la place de

Dog sparky;

et laisser le destructeur s'appeler une fois que sparky est hors de portée?

Merci!

108
demandé sur el_champo 2008-12-02 12:23:35

9 réponses

au contraire, vous devriez toujours préférer les attributions par pile, dans la mesure où en règle générale, vous ne devriez jamais avoir de nouveau/Supprimer dans votre code d'utilisateur.

comme vous le dites, lorsque la variable est déclarée sur la pile, son destructeur est automatiquement appelé lorsqu'elle sort de la portée, qui est votre outil principal pour suivre la durée de vie des ressources et éviter les fuites.

donc en général, chaque fois que vous avez besoin d'allouer une ressource, que ce soit la mémoire (en appelant new), les poignées de fichiers, les sockets ou quoi que ce soit d'autre, l'envelopper dans une classe où le constructeur acquiert la ressource, et le destructeur la libère. Ensuite, vous pouvez créer un objet de ce type sur la pile, et vous êtes garanti que votre ressource est libérée quand elle sort de la portée. De cette façon, vous n'avez pas à suivre vos nouvelles paires/supprimer partout pour vous assurer d'éviter les fuites de mémoire.

le nom le plus courant pour cet idiome est RAII

aussi regarder dans les classes de pointeur intelligent qui sont utilisés pour envelopper les pointeurs résultants sur les cas rares quand vous devez allouer quelque chose avec nouveau en dehors d'un objet RAII dédié. Vous passez le pointeur à un pointeur intelligent, qui suit ensuite sa durée de vie, par exemple par comptage de référence, et appelle le destructeur lorsque la dernière référence sort de la portée. La bibliothèque standard a std::unique_ptr pour la gestion simple basée sur la portée, et std::shared_ptr qui ne comptage de référence pour mettre en œuvre la propriété partagée.

de nombreux tutoriels démontrent l'objet l'instanciation à l'aide d'un extrait de comme ...

donc ce que vous avez découvert, c'est que la plupart des tutoriels sont nuls. ;) La plupart des tutoriels vous enseignent des pratiques de c++ minables, y compris appeler new/delete pour créer des variables quand ce n'est pas nécessaire, et vous donnent un dur temps en traçant la durée de vie de vos allocations.

158
répondu jalf 2015-06-21 16:16:17

bien qu'avoir des choses sur la pile pourrait être un avantage en termes d'allocation et de libération automatique, il a certains inconvénients.

  1. vous pourriez ne pas vouloir allouer des objets énormes sur la pile.

  2. répartition Dynamique! Considérez ce code:

#include <iostream>

class A {
public:
  virtual void f();
  virtual ~A() {}
};

class B : public A {
public:
  virtual void f();
};

void A::f() {cout << "A";}
void B::f() {cout << "B";}

int main(void) {
  A *a = new B();
  a->f();
  delete a;
  return 0;
}

"B". Voyons maintenant ce qui se passe quand on utilise Stack:

int main(void) {
  A a = B();
  a.f();
  return 0;
}

cela affichera" A", ce qui pourrait ne pas être intuitif pour ceux qui sont familiers avec Java ou d'autres langages orientés objet. La raison est que vous n'avez plus de pointeur vers une instance de B . Au lieu de cela, une instance de B est créée et copiée en a variable de type A .

certaines choses peuvent se produire de façon non intuitive, surtout quand vous êtes nouveau en C++. En C vous avez vos conseils et c'est tout. Vous savez comment les utiliser et ils font toujours la même chose. En C++, ce n'est pas le cas. Imaginez juste ce qui se passe, quand vous utilisez un dans cet exemple comme argument pour une méthode - les choses deviennent plus compliquées et cela fait une énorme différence si a est de type A ou A* ou même A& (appel par référence). De nombreuses combinaisons sont possibles et se comportent toutes différemment.

21
répondu UniversE 2018-09-01 20:23:47

Eh bien, la raison d'utiliser le pointeur serait exactement la même que la raison d'utiliser les pointeurs en C alloués avec malloc: si vous voulez que votre objet de vivre plus longtemps que votre variable!

il est même fortement recommandé de ne pas utiliser le nouvel opérateur si vous pouvez l'éviter. Surtout si vous utilisez des exceptions. En général, il est beaucoup plus sûr de laisser le compilateur gratuitement vos objets.

13
répondu PierreBdR 2008-12-02 09:25:53

j'ai vu cet anti-modèle de gens qui ne reçoivent pas tout à fait l'adresse de l'opérateur. Si ils ont besoin pour appeler une fonction avec un pointeur, ils vont toujours allouer sur le tas afin qu'ils obtiennent un pointeur.

void FeedTheDog(Dog* hungryDog);

Dog* badDog = new Dog;
FeedTheDog(badDog);
delete badDog;

Dog goodDog;
FeedTheDog(&goodDog);
13
répondu Mark Ransom 2008-12-02 17:26:27

traitez heap comme un bien immobilier très important et utilisez-le très judicieusement. La règle de base est d'utiliser la pile chaque fois que possible et d'utiliser heap chaque fois qu'il n'y a pas d'autre moyen. En attribuant les objets sur la pile vous pouvez obtenir de nombreux avantages tels que:

(1). Vous n'avez pas à vous soucier de stack unwinding en cas d'exception

(2). Vous n'avez pas à vous soucier de la fragmentation de la mémoire causée par l'attribution plus d'espace que nécessaire par votre gestionnaire de tas.

7
répondu Naveen 2015-11-12 11:46:12

la seule raison pour laquelle je m'inquiétais est que le chien est maintenant alloué sur la pile, plutôt que le tas. Donc, si le Chien est mo, vous pouvez avoir un problème,

si vous devez suivre la nouvelle route/supprimer, méfiez-vous des exceptions. Et pour cette raison, vous devriez utiliser auto_ptr ou l'un des types de pointeur intelligent boost pour gérer la durée de vie de l'objet.

5
répondu Roddy 2008-12-02 09:28:52

il n'y a pas de raison à nouveau (sur le tas) quand vous pouvez allouer sur la pile (à moins que pour une raison quelconque, vous avez une petite pile et que vous voulez utiliser le tas.

Vous pouvez envisager d'utiliser un shared_ptr (ou une de ses variantes) de la bibliothèque standard si vous ne souhaitez allouer sur le tas. Cela vous permettra de supprimer pour vous une fois que toutes les références à shared_ptr auront disparu.

1
répondu Scott Langham 2008-12-02 09:30:51

il y a une raison supplémentaire, que personne d'autre n'a mentionnée, pour laquelle vous pourriez choisir de créer votre objet dynamiquement. Les objets Dynamic, heap vous permettent d'utiliser le polymorphisme .

0
répondu dangerousdave 2017-05-23 11:54:44

J'ai eu le même problème dans Visual Studio. Vous devez utiliser:

yourClass- > classMethod ();

plutôt que:

votre classe.classemethod ();

-4
répondu Hamed 2012-08-12 23:31:47