Pourquoi devrais-je utiliser un pointeur plutôt que l’object lui-même?

Je viens d’un environnement Java et j’ai commencé à travailler avec des objects en C ++. Mais une chose me vient à l’esprit: les gens utilisent souvent des pointeurs vers des objects plutôt que les objects eux-mêmes, par exemple cette déclaration:

Object *myObject = new Object; 

plutôt que:

 Object myObject; 

Ou au lieu d’utiliser une fonction, disons testFunc() , comme ceci:

 myObject.testFunc(); 

nous devons écrire:

 myObject->testFunc(); 

Mais je ne peux pas comprendre pourquoi devrions-nous le faire de cette façon. Je suppose que cela est dû à l’efficacité et à la rapidité, car nous avons un access direct à l’adresse mémoire. Ai-je raison?

Il est très regrettable que vous voyiez une allocation dynamic si souvent. Cela montre simplement combien il y a de mauvais programmeurs C ++.

En un sens, vous avez deux questions regroupées en une seule. La première est quand devrions-nous utiliser l’allocation dynamic (en utilisant new )? La seconde est quand devrions-nous utiliser des pointeurs?

Le message important à retenir est que vous devez toujours utiliser l’outil approprié pour le travail . Dans presque toutes les situations, il y a quelque chose de plus approprié et de plus sûr que d’effectuer une allocation dynamic manuelle et / ou d’utiliser des pointeurs bruts.

Allocation dynamic

Dans votre question, vous avez démontré deux façons de créer un object. La principale différence est la durée de stockage de l’object. Lorsque vous faites un Object myObject; dans un bloc, l’object est créé avec une durée de stockage automatique, ce qui signifie qu’il sera automatiquement détruit lorsqu’il sera hors de scope. Lorsque vous faites un new Object() , l’object a une durée de stockage dynamic, ce qui signifie qu’il rest actif jusqu’à ce que vous le delete explicitement. Vous ne devez utiliser la durée de stockage dynamic que lorsque vous en avez besoin. Autrement dit, vous devriez toujours préférer créer des objects avec une durée de stockage automatique lorsque vous le pouvez .

Les deux principales situations dans lesquelles vous pourriez avoir besoin d’une allocation dynamic:

  1. Vous avez besoin de l’object pour survivre à la scope actuelle – cet object spécifique à cet emplacement de mémoire spécifique, pas une copie de celui-ci. Si vous souhaitez copier / déplacer l’object (la plupart du temps, vous devriez le faire), vous devriez préférer un object automatique.
  2. Vous devez allouer beaucoup de mémoire , ce qui peut facilement remplir la stack. Ce serait bien si nous n’avions pas à nous préoccuper de cela (la plupart du temps, vous ne devriez pas être obligé), car il est vraiment hors de scope de C ++, mais malheureusement, nous devons faire face à la réalité des systèmes que nous Je développe pour.

Lorsque vous avez absolument besoin d’allocation dynamic, vous devez l’encapsuler dans un pointeur intelligent ou un autre type qui exécute RAII (comme les conteneurs standard). Les pointeurs intelligents fournissent une sémantique de propriété des objects alloués dynamicment. Jetez un coup d’œil à std::unique_ptr et std::shared_ptr , par exemple. Si vous les utilisez de manière appropriée, vous pouvez presque entièrement éviter d’effectuer votre propre gestion de la mémoire (voir la règle de zéro ).

Pointeurs

Cependant, il existe d’autres utilisations plus générales des pointeurs bruts au-delà de l’allocation dynamic, mais la plupart ont des alternatives que vous devriez préférer. Comme précédemment, préférez toujours les alternatives à moins que vous ayez vraiment besoin de pointeurs .

  1. Vous avez besoin d’une sémantique de référence . Parfois, vous voulez passer un object en utilisant un pointeur (quelle que soit la manière dont il a été alloué) car vous souhaitez que la fonction à laquelle vous le transmettez ait access à cet object spécifique (et non à une copie). Cependant, dans la plupart des cas, vous devez préférer les types de référence aux pointeurs, car ils sont spécifiquement conçus pour cela. Notez qu’il ne s’agit pas nécessairement d’étendre la durée de vie de l’object au-delà de la scope actuelle, comme dans la situation 1 ci-dessus. Comme précédemment, si vous êtes d’accord pour transmettre une copie de l’object, vous n’avez pas besoin de sémantique de référence.

  2. Vous avez besoin d’un polymorphism . Vous pouvez uniquement appeler des fonctions de manière polymorphe (c’est-à-dire en fonction du type dynamic d’un object) via un pointeur ou une référence à l’object. Si tel est le comportement dont vous avez besoin, vous devez utiliser des pointeurs ou des références. Encore une fois, les références doivent être préférées.

  3. Vous voulez représenter qu’un object est facultatif en permettant à un nullptr d’être transmis lorsque l’object est omis. Si c’est un argument, vous devriez préférer utiliser des arguments par défaut ou des surcharges de fonctions. Sinon, vous devriez préférer utiliser un type qui encapsule ce comportement, tel que std::optional (introduit dans C ++ 17 – avec les normes C ++ antérieures, utilisez boost::optional ).

  4. Vous souhaitez découpler les unités de compilation pour améliorer le temps de compilation . La propriété utile d’un pointeur est que vous n’avez besoin que d’une déclaration en aval du type pointé (pour utiliser réellement l’object, vous aurez besoin d’une définition). Cela vous permet de découpler des parties de votre processus de compilation, ce qui peut considérablement améliorer le temps de compilation. Voir l’ idiome Pimpl .

  5. Vous devez interfacer avec une bibliothèque C ou une bibliothèque de style C. À ce stade, vous êtes obligé d’utiliser des pointeurs bruts. La meilleure chose à faire est de vous assurer que vos pointeurs bruts ne se détachent pas au dernier moment. Vous pouvez obtenir un pointeur brut à partir d’un pointeur intelligent, par exemple, en utilisant sa fonction get member. Si une bibliothèque effectue une allocation pour vous, dans laquelle elle s’attend à ce que vous vous libériez via un handle, vous pouvez souvent placer le handle dans un pointeur intelligent avec un paramètre personnalisé qui libère l’object de manière appropriée.

Il existe de nombreux cas d’utilisation pour les pointeurs.

Comportement polymorphe . Pour les types polymorphes, des pointeurs (ou références) sont utilisés pour éviter de trancher:

 class Base { ... }; class Derived : public Base { ... }; void fun(Base b) { ... } void gun(Base* b) { ... } void hun(Base& b) { ... } Derived d; fun(d); // oops, all Derived parts silently "sliced" off gun(&d); // OK, a Derived object IS-A Base object hun(d); // also OK, reference also doesn't slice 

Sémantique de référence et éviter la copie . Pour les types non polymorphes, un pointeur (ou une référence) évitera de copier un object potentiellement coûteux

 Base b; fun(b); // copies b, potentially expensive gun(&b); // takes a pointer to b, no copying hun(b); // regular syntax, behaves as a pointer 

Notez que la sémantique de déplacement de C ++ 11 peut éviter plusieurs copies d’objects coûteux dans l’argument de la fonction et en tant que valeurs de retour. Mais utiliser un pointeur les évitera définitivement et autorisera plusieurs pointeurs sur le même object (alors qu’un object ne peut être déplacé que d’une fois).

Acquisition de ressources . La création d’un pointeur sur une ressource à l’aide du new opérateur est un anti-pattern dans le C ++ moderne. Utilisez une classe de ressources spéciale (un des conteneurs Standard) ou un pointeur intelligent ( std::unique_ptr<> ou std::shared_ptr<> ). Considérer:

 { auto b = new Base; ... // oops, if an exception is thrown, destructor not called! delete b; } 

contre.

 { auto b = std::make_unique(); ... // OK, now exception safe } 

Un pointeur brut doit uniquement être utilisé comme une “vue” et ne doit en aucun cas être impliqué dans la propriété, que ce soit par création directe ou implicitement par le biais de valeurs de retour. Voir aussi cette Q & A de la FAQ C ++ .

Contrôle de la durée de vie plus fin Chaque fois qu’un pointeur partagé est copié (par exemple, en tant qu’argument de fonction), la ressource vers laquelle il pointe est conservée. Les objects réguliers (non créés par new , directement par vous ou dans une classe de ressources) sont détruits lorsqu’ils sont hors de scope.

Il y a beaucoup d’excellentes réponses à cette question, y compris les cas d’utilisation importants des déclarations avancées, du polymorphism, etc. mais je pense qu’une partie de “l’âme” de votre question ne répond pas – à savoir ce que les différentes syntaxes signifient à travers Java et C ++.

Examinons la situation en comparant les deux langues:

Java:

 Object object1 = new Object(); //A new object is allocated by Java Object object2 = new Object(); //Another new object is allocated by Java object1 = object2; //object1 now points to the object originally allocated for object2 //The object originally allocated for object1 is now "dead" - nothing points to it, so it //will be reclaimed by the Garbage Collector. //If either object1 or object2 is changed, the change will be reflected to the other 

L’équivalent le plus proche de ceci est:

C ++:

 Object * object1 = new Object(); //A new object is allocated on the heap Object * object2 = new Object(); //Another new object is allocated on the heap delete object1; //Since C++ does not have a garbage collector, if we don't do that, the next line would //cause a "memory leak", ie a piece of claimed memory that the app cannot use //and that we have no way to reclaim... object1 = object2; //Same as Java, object1 points to object2. 

Voyons la méthode C ++ alternative:

 Object object1; //A new object is allocated on the STACK Object object2; //Another new object is allocated on the STACK object1 = object2;//!!!! This is different! The CONTENTS of object2 are COPIED onto object1, //using the "copy assignment operator", the definition of operator =. //But, the two objects are still different. Change one, the other remains unchanged. //Also, the objects get automatically destroyed once the function returns... 

La meilleure façon d’y penser est que – plus ou moins – Java (implicitement) gère les pointeurs vers les objects, alors que C ++ peut gérer les pointeurs vers les objects ou les objects eux-mêmes. Il y a des exceptions à cela – par exemple, si vous déclarez des types Java “primitifs”, ce sont des valeurs réelles qui sont copiées, et non des pointeurs. Alors,

Java:

 int object1; //An integer is allocated on the stack. int object2; //Another integer is allocated on the stack. object1 = object2; //The value of object2 is copied to object1. 

Cela dit, l’utilisation de pointeurs n’est PAS nécessairement la bonne ou la mauvaise façon de gérer les choses. Cependant, d’autres réponses l’ont couvert de manière satisfaisante. L’idée générale est cependant qu’en C ++, vous avez beaucoup plus de contrôle sur la durée de vie des objects et sur l’endroit où ils vont vivre.

Prenons le sharepoint départ – la construction Object * object = new Object() est en fait ce qui se rapproche le plus de la sémantique typique de Java (ou C #).

Une autre bonne raison d’utiliser des pointeurs serait pour les déclarations avancées . Dans un projet suffisamment important, ils peuvent vraiment accélérer la compilation.

Préface

Java n’est rien comme C ++, contrairement au battage publicitaire. La machine de hype Java aimerait vous faire croire que parce que Java a une syntaxe de type C ++, les langages sont similaires. Rien ne peut être plus éloigné de la vérité. Cette désinformation est une des raisons pour lesquelles les programmeurs Java vont en C ++ et utilisent une syntaxe de type Java sans comprendre les implications de leur code.

Nous partons

Mais je ne peux pas comprendre pourquoi devrions-nous le faire de cette façon. Je suppose que cela est dû à l’efficacité et à la rapidité, car nous avons un access direct à l’adresse mémoire. Ai-je raison?

Au contraire, en fait. Le tas est beaucoup plus lent que la stack, car la stack est très simple par rapport au tas. Les variables de stockage automatiques (alias les variables de stack) ont leurs destructeurs appelés une fois qu’ils sont hors de scope. Par exemple:

 { std::ssortingng s; } // s is destroyed here 

Par contre, si vous utilisez un pointeur alloué dynamicment, son destructeur doit être appelé manuellement. delete appelle ce destructeur pour vous.

 { std::ssortingng* s = new std::ssortingng; } delete s; // destructor called 

Cela n’a rien à voir avec la new syntaxe répandue dans C # et Java. Ils sont utilisés à des fins complètement différentes.

Avantages de l’allocation dynamic

1. Vous n’avez pas besoin de connaître la taille du tableau à l’avance

L’un des premiers problèmes rencontrés par de nombreux programmeurs C ++ est que, lorsqu’ils acceptent des entrées arbitraires d’utilisateurs, vous ne pouvez allouer qu’une taille fixe à une variable de stack. Vous ne pouvez pas non plus changer la taille des tableaux. Par exemple:

 char buffer[100]; std::cin >> buffer; // bad input = buffer overflow 

Bien sûr, si vous utilisez un std::ssortingng place, std::ssortingng redimensionne en interne afin que cela ne soit pas un problème. Mais pour l’essentiel, la solution à ce problème est l’allocation dynamic. Vous pouvez allouer de la mémoire dynamic en fonction de l’entrée de l’utilisateur, par exemple:

 int * pointer; std::cout << "How many items do you need?"; std::cin >> n; pointer = new int[n]; 

Note latérale : Une erreur commise par de nombreux débutants est l’utilisation de tableaux de longueur variable. Ceci est une extension GNU et aussi une extension Clang, car elles reflètent plusieurs extensions de GCC. Il ne faut donc pas se fier à l’ int arr[n] suivant.

Comme le tas est beaucoup plus gros que la stack, on peut atsortingbuer / réallouer de manière arbitraire autant de mémoire que nécessaire, alors que la stack est limitée.

2. Les tableaux ne sont pas des pointeurs

Comment est-ce un avantage que vous demandez? La réponse deviendra claire une fois que vous aurez compris la confusion / le mythe derrière les tableaux et les pointeurs. Il est communément admis qu’ils sont identiques, mais ils ne le sont pas. Ce mythe vient du fait que les pointeurs peuvent être classés comme des tableaux et que les tableaux se désintègrent en pointeurs au niveau supérieur dans une déclaration de fonction. Cependant, une fois qu’un tableau se désintègre en un pointeur, le pointeur perd sa sizeof informations. Ainsi, sizeof(pointer) donnera la taille du pointeur en octets, qui est généralement de 8 octets sur un système 64 bits.

Vous ne pouvez pas affecter aux tableaux, mais uniquement les initialiser. Par exemple:

 int arr[5] = {1, 2, 3, 4, 5}; // initialization int arr[] = {1, 2, 3, 4, 5}; // The standard dictates that the size of the array // be given by the amount of members in the initializer arr = { 1, 2, 3, 4, 5 }; // ERROR 

D’autre part, vous pouvez faire ce que vous voulez avec des pointeurs. Malheureusement, la distinction entre les pointeurs et les tableaux étant faite à la main en Java et en C #, les débutants ne comprennent pas la différence.

3. Polymorphisme

Java et C # ont des fonctionnalités qui vous permettent de traiter les objects comme un autre, par exemple en utilisant le mot-clé as . Donc, si quelqu’un voulait traiter un object Entity tant qu’object Player , on pourrait le faire: Player player = Entity as Player; Ceci est très utile si vous avez l’intention d’appeler des fonctions sur un conteneur homogène qui ne devrait s’appliquer qu’à un type spécifique. La fonctionnalité peut être obtenue de la même manière ci-dessous:

 std::vector vector; vector.push_back(&square); vector.push_back(&sortingangle); for (auto& e : vector) { auto test = dynamic_cast(e); // I only care about sortingangles if (!test) // not a sortingangle e.GenericFunction(); else e.TriangleOnlyMagic(); } 

Donc, si seulement les Triangles avaient une fonction Rotate, ce serait une erreur du compilateur si vous essayiez de l’appeler sur tous les objects de la classe. En utilisant dynamic_cast , vous pouvez simuler le mot-clé as . Pour être clair, si une dissortingbution échoue, elle renvoie un pointeur non valide. So !test est essentiellement un raccourci pour vérifier si le test est NULL ou un pointeur invalide, ce qui signifie que la dissortingbution a échoué.

Bénéfices des variables automatiques

Après avoir vu toutes les grandes choses que l’allocation dynamic peut faire, vous vous demandez probablement pourquoi personne n’utiliserait pas toujours l’allocation dynamic? Je vous ai déjà dit une raison, le tas est lent. Et si vous n’avez pas besoin de tout ce souvenir, vous ne devriez pas en abuser. Voici donc quelques inconvénients sans ordre particulier:

  • Il est sujet aux erreurs. L’allocation manuelle de la mémoire est dangereuse et vous êtes sujet aux fuites. Si vous ne maîsortingsez pas le débogueur ou valgrind (un outil de fuite de mémoire), vous pouvez retirer vos cheveux de la tête. Heureusement, les idiomes et les pointeurs intelligents de RAII atténuent un peu cette situation, mais vous devez connaître les pratiques telles que The Rule Of Three et The Rule Of Five. Il y a beaucoup d’informations à prendre en compte, et les débutants qui ne le savent pas ou qui s’en fichent tomberont dans ce piège.

  • Ce n’est pas nécessaire. Contrairement à Java et C # où il est idiomatique d’utiliser le new mot-clé partout, en C ++, vous ne devriez l’utiliser que si vous en avez besoin. La phrase commune va, tout ressemble à un clou si vous avez un marteau. Alors que les débutants qui commencent par C ++ ont peur des pointeurs et apprennent à utiliser les variables de stack par habitude, les programmeurs Java et C # commencent par utiliser des pointeurs sans le comprendre! Cela va littéralement du mauvais pied. Vous devez abandonner tout ce que vous savez car la syntaxe est une chose, apprendre la langue en est une autre.

1. (N) RVO – Aka, optimisation de la valeur de retour (nommée)

Une optimisation faite par de nombreux compilateurs est appelée optimisation de l’ élision et de la valeur de retour . Ces éléments peuvent éviter des copies inutiles, ce qui est utile pour les objects très volumineux, tels qu’un vecteur contenant de nombreux éléments. Normalement, la pratique courante consiste à utiliser des pointeurs pour transférer la propriété plutôt que de copier les gros objects pour les déplacer . Cela a conduit à la sémantique des mouvements et aux pointeurs intelligents .

Si vous utilisez des pointeurs, (N) RVO ne se produit PAS . Il est plus avantageux et moins enclin à l’erreur de tirer parti de (N) RVO plutôt que de renvoyer ou de transmettre des pointeurs si vous êtes préoccupé par l’optimisation. Des fuites d’erreurs peuvent se produire si l’appelant d’une fonction est responsable de la delete un object alloué dynamicment, etc. Il peut être difficile de suivre la propriété d’un object si des aiguilles sont passées comme une patate chaude. Utilisez simplement les variables de stack car elles sont plus simples et meilleures.

C ++ vous propose trois méthodes pour passer un object: par pointeur, par référence et par valeur. Java vous limite avec le dernier (la seule exception est les types primitifs comme int, boolean, etc.). Si vous voulez utiliser C ++ pas simplement comme un jouet étrange, vous feriez mieux de connaître la différence entre ces trois manières.

Java prétend qu’il n’y a pas de problème tel que “qui et quand devrait détruire cela?”. La réponse est: le ramasse-miettes, génial et affreux. Néanmoins, il ne peut pas fournir une protection à 100% contre les memory leaks (oui, Java peut perdre de la mémoire ). En fait, GC vous donne une fausse impression de sécurité. Plus votre VUS est gros, plus votre évacuation est longue.

C ++ vous met en face de la gestion du cycle de vie des objects. Eh bien, il existe des moyens de gérer cela ( la famille des pointeurs intelligents , QObject dans Qt et ainsi de suite), mais aucun ne peut être utilisé de la même manière que GC: vous devez toujours garder à l’esprit la gestion de la mémoire. En plus de détruire un object, vous devez également éviter de détruire le même object plus d’une fois.

Pas encore peur? Ok: références cycliques – manipulez-les vous-même, humains. Et rappelez-vous: tuez chaque object avec précision une fois, nous ne voulons pas que ceux qui gâchent les cadavres, laissez les morts seuls.

Donc, revenons à votre question.

Lorsque vous passez votre object par valeur, non par pointeur ou par référence, vous copiez l’object (l’object entier, qu’il s’agisse d’un couple d’octets ou d’un énorme vidage de firebase database). t vous?) chaque fois que vous faites ‘=’. Et pour accéder aux membres de l’object, vous utilisez ‘.’ (point).

Lorsque vous passez votre object par un pointeur, vous ne copiez que quelques octets (4 sur des systèmes 32 bits, 8 sur des systèmes 64 bits), à savoir – l’adresse de cet object. Et pour montrer cela à tout le monde, vous utilisez cet opérateur «->» lorsque vous accédez aux membres. Ou vous pouvez utiliser la combinaison de ‘*’ et de ‘.’

Lorsque vous utilisez des références, vous obtenez le pointeur qui prétend être une valeur. C’est un pointeur, mais vous accédez aux membres via ‘.’

Et, encore une fois, quand vous déclarez plusieurs variables séparées par des virgules, alors (regardez les mains):

  • Le type est donné à tout le monde
  • Le modificateur valeur / pointeur / référence est individuel

Exemple:

 struct MyStruct { int* someIntPointer, someInt; //here comes the surprise MyStruct *somePointer; MyStruct &someReference; }; MyStruct s1; //we allocated an object on stack, not in heap s1.someInt = 1; //someInt is of type 'int', not 'int*' - value/pointer modifier is individual s1.someIntPointer = &s1.someInt; *s1.someIntPointer = 2; //now s1.someInt has value '2' s1.somePointer = &s1; s1.someReference = s1; //note there is no '&' operator: reference sortinges to look like value s1.somePointer->someInt = 3; //now s1.someInt has value '3' *(s1.somePointer).someInt = 3; //same as above line *s1.somePointer->someIntPointer = 4; //now s1.someInt has value '4' s1.someReference.someInt = 5; //now s1.someInt has value '5' //although someReference is not value, it's members are accessed through '.' MyStruct s2 = s1; //'NO WAY' the comstackr will say. Go define your '=' operator and come back. //OK, assume we have '=' defined in MyStruct s2.someInt = 0; //s2.someInt == 0, but s1.someInt is still 5 - it's two completely different objects, not the references to the same one 

En C ++, les objects alloués sur la stack (à l’aide de l’ Object object; instruction dans un bloc) ne vivront que dans la scope dans laquelle ils sont déclarés. Lorsque le bloc de code termine son exécution, l’object déclaré est détruit. Considérant que si vous allouez de la mémoire sur le tas, en utilisant Object* obj = new Object() , ils continuent à vivre en tas jusqu’à ce que vous delete obj .

Je créerais un object sur le tas quand j’aime utiliser l’object non seulement dans le bloc de code qui l’a déclaré / alloué.

Mais je ne peux pas comprendre pourquoi devrions-nous l’utiliser comme ça?

Je comparerai le fonctionnement dans le corps de la fonction si vous utilisez:

 Object myObject; 

Dans la fonction, votre myObject sera détruit une fois que cette fonction sera de retour. C’est donc utile si vous n’avez pas besoin de votre object en dehors de votre fonction. Cet object sera placé sur la stack de threads actuelle.

Si vous écrivez à l’intérieur du corps de la fonction:

  Object *myObject = new Object; 

alors l’instance de classe d’object pointée par myObject ne sera pas détruite une fois la fonction terminée et l’allocation sur le tas.

Maintenant, si vous êtes programmeur Java, le deuxième exemple est plus proche de la manière dont l’allocation d’objects fonctionne sous Java. Cette ligne: Object *myObject = new Object; est équivalent à java: Object myObject = new Object(); . La différence est que sous java, myObject récupérera les ordures, tandis que c ++ ne sera pas libéré, vous devez appeler quelque part explicitement `delete myObject; ‘ sinon vous allez introduire des memory leaks.

Depuis c ++ 11, vous pouvez utiliser des méthodes sûres d’allocation dynamic: new Object , en stockant des valeurs dans shared_ptr / unique_ptr.

 std::shared_ptr safe_str = make_shared("make_shared"); // since c++14 std::unique_ptr safe_str = make_unique("make_shared"); 

De plus, les objects sont très souvent stockés dans des conteneurs, tels que les cartes ou les vecteurs, ils gèrent automatiquement la durée de vie de vos objects.

Techniquement, il s’agit d’un problème d’allocation de mémoire, mais voici deux aspects plus pratiques. Il doit faire deux choses: 1) Scope, lorsque vous définissez un object sans pointeur, vous ne pourrez plus y accéder après le bloc de code dans lequel il est défini, alors que si vous définissez un pointeur avec “new”, alors vous peut y accéder de n’importe où vous avez un pointeur sur cette mémoire jusqu’à ce que vous appeliez “delete” sur le même pointeur. 2) If you want to pass arguments to a function you want to pass a pointer or a reference in order to be more efficient. When you pass an Object then the object is copied, if this is an object that uses a lot of memory this might be CPU consuming (eg you copy a vector full of data). When you pass a pointer all you pass is one int (depending of implementation but most of them are one int).

Other than that you need to understand that “new” allocates memory on the heap that needs to be freed at some point. When you don’t have to use “new” I suggest you use a regular object definition “on the stack”.

Well the main question is Why should I use a pointer rather than the object itself? And my answer, you should (almost) never use pointer instead of object, because C++ has references , it is safer then pointers and guarantees the same performance as pointers.

Another thing you mentioned in your question:

 Object *myObject = new Object; 

Comment ça marche? It creates pointer of Object type, allocates memory to fit one object and calls default constructor, sounds good, right? But actually it isn’t so good, if you dynamically allocated memory (used keyword new ), you also have to free memory manually, that means in code you should have:

 delete myObject; 

This calls destructor and frees memory, looks easy, however in big projects may be difficult to detect if one thread freed memory or not, but for that purpose you can try shared pointers , these slightly decreases performance, but it is much easier to work with them.


And now some introduction is over and go back to question.

You can use pointers instead of objects to get better performance while transferring data between function.

Take a look, you have std::ssortingng (it is also object) and it contains really much data, for example big XML, now you need to parse it, but for that you have function void foo(...) which can be declarated in different ways:

  1. void foo(std::ssortingng xml); In this case you will copy all data from your variable to function stack, it takes some time, so your performance will be low.
  2. void foo(std::ssortingng* xml); In this case you will pass pointer to object, same speed as passing size_t variable, however this declaration has error prone, because you can pass NULL pointer or invalid pointer. Pointers usually used in C because it doesn’t have references.
  3. void foo(std::ssortingng& xml); Here you pass reference, basically it is the same as passing pointer, but comstackr does some stuff and you cannot pass invalid reference (actually it is possible to create situation with invalid reference, but it is sortingcking comstackr).
  4. void foo(const std::ssortingng* xml); Here is the same as second, just pointer value cannot be changed.
  5. void foo(const std::ssortingng& xml); Here is the same as third, but object value cannot be changed.

What more I want to mention, you can use these 5 ways to pass data no matter which allocation way you have chosen (with new or regular ).


Another thing to mention, when you create object in regular way, you allocate memory in stack, but while you create it with new you allocate heap. It is much faster to allocate stack, but it is kind a small for really big arrays of data, so if you need big object you should use heap, because you may get stack overflow, but usually this issue is solved using STL containers and remember std::ssortingng is also container, some guys forgot it 🙂

Let’s say that you have class A that contain class B When you want to call some function of class B outside class A you will simply obtain a pointer to this class and you can do whatever you want and it will also change context of class B in your class A

But be careful with dynamic object

There are many benefits of using pointers to object –

  1. Efficiency (as you already pointed out). Passing objects to functions mean creating new copies of object.
  2. Working with objects from third party libraries. If your object belongs to a third party code and the authors intend the usage of their objects through pointers only (no copy constructors etc) the only way you can pass around this object is using pointers. Passing by value may cause issues. (Deep copy / shallow copy issues).
  3. if the object owns a resource and you want that the ownership should not be sahred with other objects.

This is has been discussed at length, but in Java everything is a pointer. It makes no distinction between stack and heap allocations (all objects are allocated on the heap), so you don’t realize you’re using pointers. In C++, you can mix the two, depending on your memory requirements. Performance and memory usage is more deterministic in C++ (duh).

 Object *myObject = new Object; 

Doing this will create a reference to an Object (on the heap) which has to be deleted explicitly to avoid memory leak .

 Object myObject; 

Doing this will create an object(myObject) of the automatic type (on the stack) that will be automatically deleted when the object(myObject) goes out of scope.

A pointer directly references the memory location of an object. Java has nothing like this. Java has references that reference the location of object through hash tables. You cannot do anything like pointer arithmetic in Java with these references.

To answer your question, it’s just your preference. I prefer using the Java-like syntax.

You shouldn’t . People (many people, sadly) write it out of ignorance.

Sometimes dynamic allocation has its place but, in the examples you give, it is wrong .

If you want to think about efficiency, then this is worse , because it introduces indirection for no good reason. This sort of programming is slower and more error-prone .

With pointers ,

  • can directly talk to the memory.

  • can prevent lot of memory leaks of a program by manipulating pointers.

One reason for using pointers is to interface with C functions. Another reason is to save memory; for example: instead of passing an object which contains a lot of data and has a processor-intensive copy-constructor to a function, just pass a pointer to the object, saving memory and speed especially if you’re in a loop, however a reference would be better in that case, unless you’re using an C-style array.

In areas where memory utilization is at its premium , pointers comes handy. For example consider a minimax algorithm, where thousands of nodes will be generated using recursive routine, and later use them to evaluate the next best move in game, ability to deallocate or reset (as in smart pointers) significantly reduces memory consumption. Whereas the non-pointer variable continues to occupy space till it’s recursive call returns a value.

I will include one important use case of pointer. When you are storing some object in the base class, but it could be polymorphic.

 Class Base1 { }; Class Derived1 : public Base1 { }; Class Base2 { Base *bObj; virtual void createMemerObects() = 0; }; Class Derived2 { virtual void createMemerObects() { bObj = new Derived1(); } }; 

So in this case you can’t declare bObj as an direct object, you have to have pointer.

“Necessity is the mother of invention.” The most of important difference that I would like to point out is the outcome of my own experience of coding. Sometimes you need to pass objects to functions. In that case, if your object is of a very big class then passing it as an object will copy its state (which you might not want ..AND CAN BE BIG OVERHEAD) thus resulting in an overhead of copying object .while pointer is fixed 4-byte size (assuming 32 bit). Other reasons are already mentioned above…

There are many excellent answers already, but let me give you one example:

I have an simple Item class:

  class Item { public: std::ssortingng name; int weight; int price; }; 

I make a vector to hold a bunch of them.

std::vector inventory;

I create one million Item objects, and push them back onto the vector. I sort the vector by name, and then do a simple iterative binary search for a particular item name. I test the program, and it takes over 8 minutes to finish executing. Then I change my inventory vector like so:

std::vector inventory;

…and create my million Item objects via new. The ONLY changes I make to my code are to use the pointers to Items, excepting a loop I add for memory cleanup at the end. That program runs in under 40 seconds, or better than a 10x speed increase. EDIT: The code is at http://pastebin.com/DK24SPeW With comstackr optimizations it shows only a 3.4x increase on the machine I just tested it on, which is still considerable.