Pourquoi ne pas le C++ ont un garbage collector?
Je ne suis pas poser cette question à cause des mérites de la collecte des ordures tout d'abord. Ma principale raison de la demande c'est que je sais que Bjarne Stroustrup a dit que C++ aura un garbage collector à un certain point dans le temps.
Avec cela dit, pourquoi n'a-t-il pas été ajouté? Il y a déjà quelques ramasseurs d'ordures pour le C++. Est-ce juste un de ces "plus facile à dire qu'à faire" type de choses? Ou existe-il d'autres raisons, il n'a pas été ajouté (et ne sera pas ajouté en C++11)?
De la croix-liens:
Juste pour clarifier, je comprends les raisons pour lesquelles C++ n'ai pas de garbage collector quand il a été créé. Je me demandais pourquoi le collecteur ne peut pas être ajouté dans.
- C'est l'un des top dix mythes sur le C++ qui est le rageux toujours. La collecte des ordures n'est pas "intégrée", mais il y a plusieurs moyens faciles de le faire en C++. Poster un commentaire parce que d'autres ont déjà répondu mieux que je ne pourrais ci-dessous 🙂
- Mais c'est tout l'intérêt de ne pas être intégré, vous devez le faire vous-même. Realibility de haut en bas : intégré, bibliothèque, home-made. J'utilise C++ moi-même, et certainement pas un hater, car c'est le meilleur langage du monde. Mais de gestion de mémoire dynamique est une douleur.
- Je ne suis pas un C++ hater je ne suis même en essayant de même dire que le C++ a besoin d'un garbage collector. Je demande parce que je sais que Bjarne Stroustrup a dit qu'il SERA ajouté et c'était juste curieux de ce que les raisons de ne pas la mettre en œuvre ont été.
- Voir aussi stackoverflow.com/questions/819425/....
- je pense qu'une meilleure question est, pourquoi une collecte des ordures stratégie n'est pas une option en c++? et pourquoi le c++0x proposition initiale ne permet pas de partiel gc dans un programme?
- Cet article Le Boehm Collecteur pour le C et le C++ du Dr Dobbs décrit un open source garbage collector qui peut être utilisé à la fois avec le C et le C++. Il traite de certaines des questions qui se posent avec l'aide d'un garbage collector avec C++ destructeurs ainsi que la Bibliothèque C Standard.
- c++11 permet, "si la mise en œuvre choisissez" apparemment: stackoverflow.com/questions/15157591/...
- Mais il n'est pas utile maintenant (voir ma réponse...) il est donc peu probable que les implémentations de investir en avoir un.
Vous devez vous connecter pour publier un commentaire.
Implicite de collecte des ordures pourrait avoir été ajouté, mais il n'a tout simplement pas faire la coupe. Probablement en raison non seulement de la mise en œuvre des complications, mais aussi grâce à des gens de ne pas être en mesure de venir à un consensus général assez rapide.
Une citation de Bjarne Stroustrup lui-même:
Il y a une bonne discussion sur le sujet ici.
Aperçu général:
C++ est très puissant et vous permet de faire presque n'importe quoi. Pour cette raison, il n'est pas automatiquement pousser beaucoup de choses sur vous qui pourrait influer sur les performances. La collecte des ordures peut être facilement mis en œuvre avec des pointeurs intelligents (les objets qui encapsulent des pointeurs avec un nombre de références, qui auto supprimer eux-mêmes lorsque le compteur de référence atteint 0).
C++ a été construit avec des concurrents dans l'esprit qui n'a pas de collecte des ordures. L'efficacité a été la principale préoccupation que le C++ n'a pour parer aux critiques en comparaison à C et les autres.
Il y a 2 types de collecte des ordures...
Explicite de collecte des ordures:
C++0x ont la collecte des ordures via des pointeurs créé avec shared_ptr
Si vous le voulez, vous pouvez l'utiliser, si vous ne voulez pas, vous n'êtes pas forcé de l'utiliser.
Vous pouvez actuellement utiliser boost:shared_ptr ainsi si vous ne voulez pas attendre pour C++0x.
Implicite de collecte des ordures:
Il n'a pas transparent de collecte des ordures bien. Il sera un point central pour l'avenir C++ specs bien.
Pourquoi Tr1 n'a pas implicite de collecte des ordures?
Il y a beaucoup de choses que tr1 de C++0x aurait dû, Bjarne Stroustrup dans de précédentes interviews a déclaré que tr1 n'avait pas comme beaucoup comme il l'aurait souhaité.
smart_ptr's
? Comment feriez-vous un faible niveau de style Unix bifurcation, avec un garbage collector dans le chemin? D'autres choses seraient touchés comme le filetage. Python a ses global interprète de verrouillage surtout à cause de la collecte des déchets (voir Cython). Garder hors de C / C++, merci.void *
système d'exploitation de l'API opaque structures?std::shared_ptr
) est cyclique références, ce qui cause une fuite de mémoire. Par conséquent, vous devez soigneusement utilisationstd::weak_ptr
de briser les cycles, ce qui est pénible. Marque et de balayage de style GC n'ont pas ce problème. Il n'y a pas d'incompatibilité inhérente entre le filetage/bifurquer et de collecte des ordures. Java et C# les deux ont une haute performance de préemption le multithreading et et un garbage collector. Il y a des problèmes liés à des applications temps-réel et un garbage collector, comme la plupart des éboueurs arrêter le monde.std::shared_ptr
) est cyclique références" et terribles à la performance qui est ironique, parce que l'amélioration des performances est généralement la justification de l'utilisation de C++... flyingfrogblog.blogspot.co.royaume-uni/2011/01/...free
à unmalloc/calloc
. Au classement, l'auteur de quelque chose comme une texture de l'objet peut tout faire parfaitement, pour allouer de la texture et de supprimer toutes les références qu'il a créé, à l'heure qu'il est retiré -- absolument parfait, de l'unité testée. Et pourtant, il pourrait encore y avoir des centaines de lieux de la fuite de la texture -- tout ce qu'il faut en GC pour la texture de ressources pour...free
à unmalloc
. Ils n'apparaissent pas dans valgrind, par exemple, car ils sont logiques fuites plutôt que physique des fuites.free
et puis un autre hasard développeur utilise cette référence et vous avez tous de profiter de débogage de la undefined behavior mise à mort de vos chats et la gravure de vos maisons. Alors que valgrind trouve la référence et l'accès à code, je ne vois pas comment il est plus facile que l'analyse de la fuite de mémoire, vous obtiendrez de la cg à la place.Pour ajouter au débat ici.
Il y a des problèmes connus avec la collecte des ordures, et de les comprendre permet de comprendre pourquoi il n'y a aucune en C++.
1. La Performance ?
La première plainte est souvent question de performance, mais la plupart des gens n'ont pas vraiment conscience de ce qu'ils sont en train de parler. Comme illustré par
Martin Beckett
le problème peut ne pas être la performance en soi, mais la prévisibilité de la performance.Actuellement, il existe 2 familles de GC, qui sont largement déployés:
La
Mark And Sweep
est plus rapide (moins d'impact sur les performances d'ensemble) mais il souffre d'un "gel du monde" syndrome: c'est à dire lorsque le GC coups de pied dans, tout le reste est arrêté jusqu'à ce que le GC a fait son nettoyage. Si vous souhaitez créer un serveur qui répond en quelques millisecondes... certaines transactions ne sera pas à la hauteur de vos attentes 🙂Le problème de
Reference Counting
est différent: comptage de références ajoute-dessus, surtout en Multi-Threading environnements parce que vous devez avoir atomique comte. En outre il y a le problème des cycles de référence si vous avez besoin d'un algorithme intelligent pour détecter les cycles et les éliminer (généralement mise en œuvre par le "gel du monde" aussi, bien que moins fréquent). En général, à compter d'aujourd'hui, ce genre (même si normalement plus réactif, ou plutôt, le gel de moins en moins souvent) est plus lent que leMark And Sweep
.J'ai vu un papier par Eiffel maîtres d'œuvre qui ont essayé de mettre en œuvre un
Reference Counting
Garbage Collector qui sont similaires performance globale deMark And Sweep
sans le "Gel Du Monde" aspect. Il faut un thread séparé pour le GC (typique). L'algorithme a été un peu effrayant (à la fin), mais le papier fait un bon travail de l'introduction des concepts à la fois et en montrant l'évolution de l'algorithme de la "simple" version à part entière de l'un. Lecture recommandée si seulement je pouvais mettre ma main sur le fichier PDF...2. L'Acquisition De Ressources Est D'Initialisation
Il s'agit d'un idiome dans
C++
que vous enveloppez-la propriété des ressources à l'intérieur d'un objet pour s'assurer qu'ils sont correctement libérées. Il est principalement utilisé pour la mémoire puisque nous n'avons pas de collecte des ordures, mais il est aussi très utile quand même pour beaucoup d'autres situations:L'idée est de bien contrôler la durée de vie de l'objet:
Le problème de la GC, c'est que si elle contribue à l'ancienne et, finalement, des garanties plus tard... cette "ultime" peut ne pas être suffisant. Si vous relâche un verrou, vous voulez vraiment qu'il soit libéré, de sorte qu'il ne bloque pas les appels supplémentaires!
Langues avec les GC ont deux solutions:
using
construire... mais c'est explicite (faible) RAII alors qu'en C++ RAII est implicite, de sorte que l'utilisateur NE peut pas involontairement font l'erreur (en omettant lesusing
mot-clé)3. Pointeurs Intelligents
Pointeurs intelligents apparaissent souvent comme une balle d'argent à gérer la mémoire dans
C++
. Souvent de fois j'ai entendu: nous n'avons pas besoin GC après tout, puisque nous avons des pointeurs intelligents.On ne pouvait pas être plus faux.
Pointeurs intelligents faire aider:
auto_ptr
etunique_ptr
utilisation RAII concepts, très utile en effet. Ils sont si simples que vous pouvez écrire vous-même très facilement.Quand un besoin de partager la propriété toutefois, il devient de plus en plus difficile: vous risquez de partager entre plusieurs threads et il ya quelques questions subtiles avec la manipulation de la comte. Donc, on va naturellement vers
shared_ptr
.C'est génial, c'est ce coup de pouce pour après tout, mais ce n'est pas une balle d'argent. En fait, le principal problème avec les
shared_ptr
est qu'il émule un GC mis en œuvre parReference Counting
mais vous avez besoin pour mettre en œuvre le cycle de détection de tous par vous-même... UrgBien sûr, il y a cette
weak_ptr
truc, mais j'ai malheureusement déjà vu des fuites de mémoire en dépit de l'utilisation deshared_ptr
en raison de ces cycles... et quand vous êtes dans un environnement multithread, il est extrêmement difficile à détecter!4. Quelle est la solution ?
Il n'y a pas de solution miracle, mais comme toujours, c'est certainement faisable. En l'absence de GC besoin d'être clair sur la propriété:
weak_ptr
Donc en effet, il serait bon d'avoir un GC... mais c'est pas une question triviale. Et dans le même temps, nous avons juste besoin de retrousser nos manches.
new
, les remplit avec certaines données, convertit leur adresse, les numéros, les affiche de 1/60 de seconde, puis abandonne les objets sans procéder à undelete
. Le programme plus tard permet à l'utilisateur de taper un nombre, convertit une adresse, et l'utilise sur l'hypothèse qu'il représente un objet valide. Si le numéro de l'utilisateur tape dans a été affiché comme l'adresse d'un objet, la norme C++ exige que l'adresse est toujours valide.Quel type? devrait-il être optimisé pour les systèmes embarqués machine à laver les contrôleurs, les téléphones portables, stations de travail ou les supercalculateurs?
Faut-il privilégier la réactivité de l'interface graphique ou la charge serveur?
faut-il utiliser beaucoup de mémoire ou il y a beaucoup de CPU?
C/c++ est utilisé dans de trop nombreuses circonstances différentes.
Je soupçonne quelque chose comme des pointeurs intelligents de boost sera suffisant pour la plupart des utilisateurs
Edit - Automatique éboueurs ne sont pas tellement un problème de performance, vous pouvez toujours acheter plus de serveur) c'est une question d'être prévisible performance.
Ne sachant pas quand le GC va à coup de pied dans est comme employant un neuroleptique de pilote de ligne, la plupart du temps, ils sont grands, mais quand vous avez vraiment besoin de réactivité!
L'une des plus grandes raisons que le C++ n'est pas construit dans la collecte des ordures est que l'obtention de la collecte des ordures à jouer gentil avec les destructeurs est vraiment, vraiment dur. Autant que je sache, personne ne sait vraiment comment le résoudre complètement encore. Il ya beaucoup de questions à traiter:
Ce sont quelques-uns des problèmes rencontrés.
Dispose
sur un objet peuvent rendre inutilisables, mais les références, qui fait référence à l'objet lorsqu'il était vivant continuera de le faire après c'est mort. En revanche, dans les systèmes du GC, les objets peuvent être supprimés alors que les références existent, et il y a rarement une limite sur les ravages que peut être infligée si l'un de ces références est utilisé.Bien que ce soit un vieux question, il y a encore un problème que je ne vois personne s'étant adressé à tous: la collecte des ordures est presque impossible à préciser.
En particulier, la norme C++ est assez prudent de spécifier la langue dans les termes de l'extérieur et les comportements observables, plutôt que la façon dont la mise en œuvre réalise que le comportement. Dans le cas de la collecte des ordures, cependant, il y est pratiquement pas de l'extérieur et les comportements observables.
La idée générale de la collecte des ordures, c'est qu'il doit faire un effort raisonnable pour s'assurer qu'une allocation de mémoire va réussir. Malheureusement, il est quasiment impossible de garantir que toute allocation de mémoire va réussir, même si vous avez un garbage collector en fonctionnement. Cela est vrai dans une certaine mesure en tout cas, elle l'est tout particulièrement dans le cas de C++, parce que c'est (probablement) pas possible d'utiliser une copie du collecteur (ou quelque chose de similaire) qui déplace les objets en mémoire au cours d'un cycle de collecte.
Si vous ne pouvez pas déplacer des objets, vous ne pouvez pas en créer une seule, la mémoire contiguë de l'espace pour faire vos allocations -- et cela signifie que votre tas (ou free store, ou ce que vous préférez l'appeler) peut, et devrait, être fragmentés au fil du temps. Ceci, à son tour, peut empêcher une allocation de réussir, même quand il n'y a plus de mémoire libre que le montant demandé.
Alors qu'il pourrait être possible de venir avec certains garantie qui dit (en substance) que si vous répétez exactement le même modèle de répartition à plusieurs reprises, et il a réussi la première fois, il va continuer à réussir sur les itérations suivantes, à condition que la mémoire allouée est devenu inaccessible entre les itérations. C'est comme une faiblesse de la garantie c'est essentiellement inutile, mais je ne vois pas d'espoir raisonnable de le renforcer.
Même ainsi, il est plus fort que ce qui a été proposé pour le C++. Le proposition précédente [avertissement: PDF] (qui a chuté) n'a pas de garantie de quoi que ce soit. En 28 pages de la proposition, ce que vous avez dans la voie de l'extérieur et les comportements observables a qu'un seul (non normatif) note disant:
Au moins pour moi, cela soulève un grave question sur le retour sur investissement. Nous voulons briser le code existant (personne n'est sûr de combien exactement, mais certainement un peu), imposent de nouvelles exigences sur la mise en œuvre et de nouvelles restrictions sur le code, et ce que nous obtenons en retour est peut-être rien du tout?
Même, au mieux, ce que nous obtenons sont des programmes qui, basé sur test avec Java, aura probablement besoin d'environ six fois plus de mémoire pour fonctionner à la même vitesse qu'ils font maintenant. Pire, la collecte des ordures a été une partie de Java depuis le début -- C++ endroits assez plus de restrictions sur le garbage collector qu'il sera presque certainement avoir une même pire rapport coût/bénéfice (même si nous allons au-delà de ce que la proposition de la garantie et de supposer qu'il y aurait quelques avantages).
Je voudrais résumer la situation mathématiquement: ce une situation complexe. Comme tout mathématicien sait, un nombre complexe est composé de deux parties: le réel et l'imaginaire. Il me semble que ce que nous avons ici sont des coûts qui sont réels, mais les avantages qui sont (au moins pour la plupart) de l'imaginaire.
free
pour vous (où je veux direfree
comme pour le langage C). Mais Java ne garantit jamais à appeler les finaliseurs ou quelque chose comme ça. En fait, le C++ ne prend beaucoup plus de Java à courir autour de commettre des écritures de base de données, bouffées de chaleur descripteurs de fichiers, et ainsi de suite. Java prétend avoir "GC", mais les développeurs de Java méticuleuse appelclose()
tous les temps et ils doivent être très conscients de la gestion des ressources, en faisant attention de ne pas appelerclose()
trop tôt ou trop tard. C++ nous libère de que. ...(suite)try (Whatever w=...) {...}
elle n'en résout (et vous obtenez un avertissement lorsque vous oubliez). Les autres sont problématiques, RAII, trop. L'appel declose()
"tout le temps" signifie peut-être une fois par des dizaines de milliers de lignes, ce qui n'est pas si mal que ça, alors que la mémoire est attribué à peu près sur tous les Java ligne.Source: http://www.stroustrup.com/bs_faq.html#garbage-collection
Quant à savoir pourquoi il ne l'a construit dans, Si je me souviens bien, il a été inventé avant le GC a été le chose, et je ne crois pas que la langue pourrait avoir eu des GC pour plusieurs raisons(I. E vers l'Arrière de compatibilité avec C)
Espère que cette aide.
Stroustrup fait quelques bons commentaires sur ce en 2013, les Natifs de la conférence.
Il suffit de sauter à propos de 25m50s dans cette vidéo. (Je vous recommande de regarder la vidéo en entier effectivement, mais cela saute aux choses à propos de la collecte des ordures.)
Lorsque vous avez vraiment une grande langue qui le rend facile (et sûr et prévisible, et facile à lire et facile à apprendre) pour traiter des objets et des valeurs d'une manière directe, en évitant (explicite) de l'utilisation du tas, alors vous n'avez même pas voulez la collecte des ordures.
Avec C++ moderne, et les choses que nous avons en C++11, la collecte des ordures n'est plus souhaitable, sauf dans des circonstances limitées. En fait, même si une bonne garbage collector est l'un des principaux compilateurs C++, je pense qu'il ne sera pas utilisé très souvent. Il sera plus facile, pas plus dur, pour éviter la GC.
Il montre cet exemple:
C'est dangereux en C++. Mais c'est aussi dangereux en Java! En C++, si la fonction retourne au début, le
delete
ne sera jamais appelé. Mais si vous avez eu plein de collecte des ordures, comme en Java, il vous suffit simplement faire une suggestion que l'objet sera détruite "à un certain moment dans l'avenir" (mise à Jour:, c'est même pire que cela. Java ne pas promesse d'appeler le finaliseur jamais - peut-être ne jamais être appelé). Ce n'est pas assez bon si Gadget est titulaire d'un descripteur de fichier ouvert, ou d'une connexion à une base de données, ou des données que vous avez mis en mémoire tampon pour écrire dans une base de données à un moment plus tard. Nous voulons que le Gadget à être détruits dès que c'est fini, afin de libérer ces ressources dès que possible. Vous ne voulez pas que votre serveur de base de données aux prises avec des milliers de connexions de base de données qui ne sont plus nécessaires - il ne sait pas que votre programme est terminé de travailler.Alors quelle est la solution? Il existe quelques approches. L'approche évidente, que vous utiliserez pour la grande majorité de vos objets est:
Cela prend moins de caractères à taper. Il n'a pas
new
obtenir de la manière. Il ne nécessite pas le type deGadget
deux fois. L'objet est détruit à la fin de la fonction. Si c'est ce que vous voulez, c'est très intuitif.Gadget
s ont le même comportement queint
oudouble
. Prévisible, facile à lire, facile à enseigner. Tout est une "valeur". Parfois une grande valeur, mais les valeurs sont plus faciles à enseigner, car vous n'avez pas cette "action à distance" chose que vous obtenez avec des pointeurs (ou références).La plupart des objets sont à utiliser uniquement dans la fonction qui les a créés, et peut-être passé comme entrées des fonctions enfant. Le programmeur ne devrait pas avoir à penser à la gestion de la mémoire " quand le retour des objets, ou partager des objets dans l'ensemble largement séparés les parties du logiciel.
Portée et durée de vie sont importantes. La plupart du temps, c'est plus facile si la durée de vie est le même que le champ d'application. C'est plus facile à comprendre et plus facile à enseigner. Quand vous voulez une autre vie, il devrait être évident à la lecture du code que vous faites cela, par l'utilisation de
shared_ptr
par exemple. (Ou retour (grand) des objets par valeur, en tirant parti de déménagement de la sémantique ou deunique_ptr
.Cela peut sembler comme un problème d'efficacité. Que faire si je souhaite retourner un Gadget de
foo()
? C++11 de la sémantique de déplacement, de faciliter le retour de grands objets. Il suffit d'écrireGadget foo() { ... }
et il va juste travailler, et de travailler rapidement. Vous n'avez pas besoin de jouer avec&&
vous-même, juste retour des choses par la valeur et la langue sera souvent en mesure de faire le nécessaire optimisations. (Même avant le C++03, compilateurs fait un très bon travail en évitant la copie inutile.)Comme Stroustrup dit ailleurs dans la vidéo (paraphrase): "Seulement un informaticien voudrais insister sur la copie d'un objet, puis de détruire l'original. (le public rit). Pourquoi ne pas simplement déplacer l'objet directement vers le nouvel emplacement? C'est ce que les humains (non informaticiens) attendre."
Quand vous pouvez garantir qu'une seule copie d'un objet est nécessaire, il est beaucoup plus facile de comprendre la vie de l'objet. Vous pouvez choisir ce que la durée de vie de la politique que vous voulez, et la collecte des ordures est là, si vous le souhaitez. Mais quand vous comprenez les avantages des autres approches, vous trouverez que la collecte des ordures est au bas de votre liste de préférences.
Si cela ne fonctionne pas pour vous, vous pouvez utiliser
unique_ptr
, ou, à défaut,shared_ptr
. Bien écrit en C++11 est plus court, plus facile à lire, et plus faciles à enseigner que beaucoup d'autres langues quand il s'agit de la gestion de la mémoire.Gadget
ne demande pas autre chose à faire n'importe quoi en son nom, le code d'origine serait parfaitement en sécurité dans Java si le sens (pour Java)delete
déclaration ont été supprimés.shared_ptr<T>
spécialement lorsqueT
est "ennuyeux". Il pourrait décider de ne pas réellement gérer un ref compteur de ce type, et au lieu d'utiliser GC. Cela permettrait à la GC pour être utilisé sans le développeur qui a besoin d'avis. Unshared_ptr
pourrait tout simplement être vu comme une table de pointeur, pour adaptéT
. Mais il y a des limites dans ce domaine, et il ferait beaucoup de programmes plus lent.string1=string2;
va exécuter très rapidement quelle que soit la longueur de la chaîne (c'est littéralement rien de plus qu'un registre de charger et d'enregistrer store), et ne nécessite pas de verrouillage pour s'assurer que si la déclaration ci-dessus est exécutée alors questring2
est en cours d'écriture,string1
tiendra la valeur ancienne ou la nouvelle valeur, sans un Comportement Indéfini).shared_ptr<String>
nécessite beaucoup de derrière-le-scènes de la synchronisation, et l'attribution d'unString
peut se comporter bizarrement si une variable est de lire et d'écrire simultanément. Les cas où l'on aurait envie d'écrire et de lire unString
simultanément ne sont pas très commun, mais peuvent survenir si, par exemple, du code souhaite faire des cours des rapports d'état à la disposition des autres threads. Dans .NET et Java, de telles choses juste "travail".String
classe qui est immuable, tout comme la classe String en Java? Et, par conséquent, vous n'avez jamais vraiment attribuer à une Chaîne. Vous pouvez affecter à unString*
ou unshared_ptr<String>
(ou d'une Chaîne de caractères Java-référence en Java). Je suis confus au sujet de votre discussion de "cession" et "lire et écrire", parce que je préfère la clarté que l'objet sous-jacent est immuable.String
, immuable type de référence qui est utilisé, car c'est la seule chose qui peut donner de la valeur sémantique de Java, et la seule chose qui pourrait donner de la valeur sémantique .NET sans excès de boxe [dans .NET, une structure qui rend unchar[]
peut-être mieux que tas objet, sauf pour la boxe problème]. Pour fins de comparaison, je dirais que doit être comparé avec quel que soit le type en C++ le plus efficace pour représenter...String
serait le mieux; pour d'autres,shared_ptr<string>
serait mieux. Il y a quelques modèles d'utilisation, cependant, pour laquelle aucun C++, type peuvent atteindre l'efficacité et de la sémantique de la GC chaînes, puisque la seule synchronisation est nécessaire avec la GC lui-même, et il a des pouvoirs magiques pour forcer la synchronisation avec des fils qui n'ont pas d'autres mécanismes de synchronisation intégrée.String
immuable? Vous avez dit plus tôt au sujet de la lecture et de l'écriture, mais l'écriture n'a pas de sens avec un immuableString
. quelque chose commeusing String = const std::vector<char>;
. Je ne peux pas penser à d'autres questions avant d'être clair que le type est.f()+g()
n'est pas déterministe, Java règles parce qu'il est déterministe" de la foule.L'idée derrière C++, vous ne paierez aucun impact sur les performances pour les fonctionnalités que vous n'utilisez pas. Ainsi, l'ajout de la collecte des ordures aurait signifié avoir certains programmes de s'exécuter directement sur le matériel, la façon dont C ne et certains, dans une sorte d'exécution de la machine virtuelle.
Rien ne vous empêche d'utiliser une certaine forme de pointeurs intelligents qui sont liés à certains tiers mécanisme de collecte des déchets. Je me souviens de Microsoft de faire quelque chose comme ça avec COM et que ça ne va pas bien.
Pour répondre à la plupart des "pourquoi" des questions à propos de C++, lire La conception et l'Évolution de C++
Parce que C++ moderne n'a pas besoin de la collecte des ordures.
Bjarne Stroustrup de la FAQ de la réponse à cette question, dit:
La situation, pour le code écrit ces jours (C++17 et suivants de l'officiel Lignes Directrices De Base) est comme suit:
"Ah ouais? Mais qu'en est...
... si je viens d'écrire le code de la façon dont nous avons utilisé pour écrire en C++ dans les vieux jours?"
En effet, vous pourrait il suffit de les ignorer toutes les lignes directrices et d'écriture qui fuit le code de l'application et sera de compiler et d'exécuter (et de fuite), comme toujours.
Mais ce n'est pas un "juste ne pas faire" de la situation, où le développeur est prévu pour être vertueux et exercer beaucoup de contrôle de soi, c'est juste pas plus simple d'écrire non conforme au code, ni est-il plus rapide à écrire, ni est-il un meilleur rendement. Progressivement, il sera aussi plus difficile à écrire, comme vous le feriez pour faire face à une hausse "d'adaptation d'impédance" avec ce conforme code offre et attend.
... si je
reintrepret_cast
? Ou faire de l'arithmétique des pointeurs? Ou d'autres hacks?"En effet, si vous mettez votre esprit à lui, vous pouvez écrire du code qui sème la pagaille en dépit de jouer gentil avec les lignes directrices. Mais:
... le développement des bibliothèques?"
Si vous êtes une bibliothèque C++ développeur ensuite, vous écrivez le code unsafe impliquant des premières pointeurs, et vous êtes tenus de code avec soin et de manière responsable, mais elles sont autonomes, des morceaux de code écrites par des experts (et, plus important encore, revu par les experts).
Donc, c'est juste comme Bjarne dit: Il n'y a vraiment aucune motivation pour ramasser les ordures en général, comme vous tous, mais assurez-vous de ne pas produire de déchets. GC est en train de devenir un non-problème en C++.
Qui n'est pas à dire que GC n'est pas un problème intéressant pour certaines applications spécifiques, lorsque vous souhaitez employer allocation personnalisé et de-les allocations de stratégies. Pour ceux que vous voulez personnalisée d'allocation et de répartition, pas une langue au niveau de la cg.
L'un des principes fondamentaux sur lesquels repose l'origine du langage C est que la mémoire est composée d'une séquence d'octets, et le code ont uniquement besoin de soins sur le contenu de ces octets est-à dire au moment précis où ils sont utilisés. Moderne C permet de compilateurs pour imposer des restrictions supplémentaires, mais C comprend--et C++ conserve--la possibilité de décomposer un pointeur dans une séquence d'octets, de les assembler une séquence d'octets contenant les mêmes valeurs dans un pointeur, puis utilisez le pointeur pour accéder le plus tôt objet.
Alors que cette aptitude peut être utile, voire indispensable dans certains types d'applications, une langue que comprend cette capacité sera très limitée dans sa capacité à soutenir toute sorte d'informations utiles et fiables de collecte des ordures. Si un compilateur ne sait pas tout ce qui a été fait avec les morceaux qui ont fait un pointeur, il n'aura aucun moyen de savoir si des informations suffisantes pour reconstruire le pointeur peut exister quelque part dans l'univers. Car il serait possible pour que les informations soient stockées dans les moyens que l'ordinateur ne serait pas en mesure d'accéder, même si elle savait à leur sujet (par exemple, les octets qui composent le pointeur peut avoir été montré à l'écran assez longtemps pour que quelqu'un à les écrire sur un morceau de papier), il peut être littéralement impossible pour un ordinateur pour savoir si un pointeur pourrait éventuellement être utilisé dans l'avenir.
Une intéressante caprice de nombreux garbage collector de cadres est qu'un objet de référence non définie par les modèles de bits qui y sont contenues, mais par la relation entre les bits tenu de l'objet de référence et d'autres informations ailleurs. En C et C++, si le motif de bits stockés dans un pointeur identifie un objet, que le motif de bits permettra d'identifier cet objet jusqu'à ce que l'objet est explicitement détruit. Dans un typique GC système, un objet peut être représenté par une séquence de bits 0x1234ABCD à un moment donné dans le temps, mais la prochaine GC cycle pourrait remplacer toutes les références à 0x1234ABCD avec des références à des 0x4321BABE, après quoi l'objet est représenté par le dernier modèle. Même si l'on afficher la séquence de bits associé à un objet de référence, puis plus tard le lire à partir du clavier, il n'y aurait aucun espoir que le même modèle de bits pourrait être utilisée pour identifier le même objet (ou un objet).
Toutes les techniques qui parle de surcharger le concept.
Si vous mettez GC en C++ pour la mémoire automatiquement, pensez à quelque chose comme un navigateur web. Le navigateur doit charger un complet de documents web ET d'exécuter des scripts web. Vous pouvez stocker web script variables dans l'arborescence du document. Dans un GRAND document dans un navigateur avec plusieurs onglets ouverts, cela signifie que chaque fois que le GC doit faire une collection complète, il faut aussi analyser tous les éléments d'un document.
Sur la plupart des ordinateurs, ce qui signifie que les DÉFAUTS de PAGE va se produire. Donc, la raison principale, pour répondre à la question, c'est que les DÉFAUTS de PAGE va se produire. Vous le saurez quand votre PC commence à faire beaucoup d'accès disque. C'est parce que le GC doit toucher beaucoup de mémoire pour prouver pointeurs invalides. Lorsque vous avez une véritable demande en utilisant beaucoup de mémoire, ayant pour analyser tous les objets de chaque collection est le chaos à cause des DÉFAUTS de PAGE. Un défaut de page est lorsque la mémoire virtuelle a besoin pour aller lire dans la mémoire vive sur le disque.
Donc la bonne solution est de diviser une application dans les parties qui doivent GC et les pièces qui ne le sont pas. Dans le cas du navigateur web exemple ci-dessus, si le document de l'arbre a été alloué avec malloc, mais le javascript a couru avec GC, puis à chaque fois que la GC coups de pied dans l'analyse uniquement une petite partie de la mémoire PAGINÉE éléments de la mémoire de l'arborescence du document n'a pas besoin d'obtenir paginé de retour dans.
À mieux comprendre ce problème, chercher de la mémoire virtuelle et la façon dont il est mis en œuvre dans les ordinateurs. Il est tout au sujet du fait que 2GO est disponible dans le programme quand il n'y a pas vraiment de beaucoup de mémoire vive. Sur les ordinateurs modernes, avec 2 go de RAM pour un système 32 bits, il n'est pas un problème à condition qu'un programme est en cours d'exécution.
Comme autre exemple, considérons une collection complète qui doit retrouver tous les objets. Vous devez d'abord analyser tous les objets accessibles via les racines. Deuxième analyse tous les objets visibles à l'étape 1. Puis balayez l'attente des destructeurs. Ensuite, allez à toutes les pages, encore et éteindre tous les objets invisibles. Cela signifie que le nombre de pages peut obtenir échangé et en arrière plusieurs fois.
Donc, ma réponse à apporter, il court, c'est que le nombre de DÉFAUTS de PAGE qui se produisent à la suite de toucher à toutes les causes de la mémoire full GC pour tous les objets dans un programme irréalisable et donc le programmeur doit afficher GC comme une aide pour des choses comme les scripts de base de données et de travail, mais faire des choses normales avec le manuel de gestion de la mémoire.
Et l'autre raison très importante est bien sûr variables globales. Pour le collecteur de savoir qu'une variable globale pointeur se trouve dans la GC, elle aurait besoin de mots-clés spécifiques, et ainsi le code C++ existant ne fonctionnerait pas.
RÉPONSE COURTE:
Nous ne savons pas comment faire la collecte des ordures efficacement (avec de légères temps et de l'espace, les frais généraux) et correctement tout le temps (dans tous les cas possibles).
RÉPONSE LONGUE:
Tout comme le C, le C++ est un des systèmes de la langue; cela signifie qu'il est utilisé lorsque vous écrivez du code dans le système, par exemple, le système d'exploitation. En d'autres termes, le C++ est conçu, exactement comme en C, avec le meilleur possible performance comme cible principale. La langue standard ne permet pas d'ajouter une fonctionnalité qui pourrait nuire à l'objectif de rendement.
Ce met en pause la question: Pourquoi la collecte des ordures diminue les performances? La raison principale est que, quand il s'agit de la mise en œuvre, nous [les scientifiques de l'informatique] je ne sais pas comment faire la collecte des ordures avec un minimum de frais généraux, pour tous les cas. Par conséquent, il est impossible de le compilateur C++ et système d'exécution pour effectuer la collecte des ordures efficace de tous les temps. D'autre part, un programmeur C++, devrait connaître sa conception/mise en œuvre et il est la meilleure personne à décider de la meilleure façon de faire de la collecte des déchets.
Dernier, si le contrôle (matériel, détails, etc.) et de la performance (temps, espace, énergie, etc.) ne sont pas les principales contraintes, puis C++ n'est pas l'écriture de l'outil. D'autres langues pourraient servir au mieux et d'offrir plus de [hidden] runtime de gestion, avec le nécessaire de frais généraux.
Lorsque vous comparez le C++ et Java, vous pouvez voir immédiatement que le C++ n'a pas été conçu avec implicite de Collecte des Ordures à l'esprit, alors que Java a été.
Avoir des choses comme arbitraire des pointeurs en C-Style et déterministe destructeurs n'est pas seulement de ralentir la performance de la GC-implémentations, il pourrait aussi détruire la compatibilité descendante pour une grande quantité de C++-legacy-code.
En plus de cela, le C++ est un langage qui est destiné à exécuter en tant qu'exécutable autonome au lieu d'avoir un complexe de l'environnement d'exécution.
Dans l'ensemble:
Oui, il serait possible d'ajouter de Collecte des Ordures pour le C++, mais par souci de continuité, il est préférable de ne pas le faire. Le coût de l'inaction serait supérieur au bénéfice.
Principalement pour deux raisons:
C++ offre déjà le manuel de gestion de la mémoire, l'allocation de pile, RAII, conteneurs, automatique pointeurs, pointeurs intelligents... Qui devrait être suffisant. Les éboueurs sont pour les programmeurs paresseux qui ne veulent pas passer 5 minutes pour penser à qui devrait propres objets ou lorsque les ressources devraient être libérés. Ce n'est pas la façon dont nous faisons les choses en C++.
Imposant la collecte des ordures est vraiment d'un niveau bas à un niveau élevé de paradigme.
Si vous regardez la façon dont les chaînes sont traitées dans une langue avec la collecte des ordures, vous trouverez, elles ne permettent de haut niveau des fonctions de manipulation de chaîne et ne permettent pas l'accès binaire à cordes. Simplement, tous les fonctions de chaîne, vérifiez d'abord les pointeurs pour voir où la chaîne est, même si vous êtes seulement en dessin sur un octet. Donc, si vous faites une boucle qui traite chaque octet dans une chaîne de caractères dans une langue avec la collecte des ordures, il doit calculer l'emplacement de la base de plus de décalage pour chaque itération, car il ne peut pas savoir quand la chaîne s'est déplacé. Ensuite, vous devez penser à des tas, des piles, des fils, etc etc.