Il y a quelques algorithmes qui sont compliquées/inefficace/impossible d'écrire sans un GC. Je suppose que c'est le point de vente majeur pour les GC en C++, et ne peut jamais le voir utilisé comme un usage général de l'allocateur.
Pourquoi pas un usage général de l'allocateur?
Tout d'abord, Nous avons RAII, et la plupart (dont moi) pensent que c'est une méthode supérieure de la gestion des ressources. Nous comme le déterminisme, car il permet d'écrire des solides, étanches code beaucoup plus simple et permet des performances prévisibles.
Deuxièmement, vous aurez besoin de placer quelques très des nations unies-C++comme des restrictions sur la façon dont vous pouvez utiliser de la mémoire. Par exemple, vous avez besoin d'au moins un accessible, onu-obfuscation pointeur. Obfuscation des pointeurs, comme le sont populaires dans les communes de l'arbre contenant les bibliothèques (à l'aide de l'alignement-bas garantis bits pour la couleur des drapeaux), entre autres, de ne pas être reconnaissable par le GC.
Lié à cela, les choses qui rendent moderne GCs donc utilisable vont être très difficile à appliquer pour C++ si vous soutien de tout nombre d'obfuscation des pointeurs. De générations en défragmentant les tables sont vraiment cool, parce que l'allocation est extrêmement bon marché (essentiellement juste incrémenter un pointeur) et éventuellement de votre allocations obtenir compactée dans quelque chose de plus petit avec l'amélioration de la localité. Pour ce faire, les objets doivent être mobiles.
Pour rendre un objet en toute sécurité mobile, le GC doit être en mesure de mettre à jour tous les liens vers elle. Il ne sera pas en mesure de trouver d'obfuscation ceux. Cela pourrait être accueillis, mais ne serait pas assez (probablement un gc_pin
type ou similaire, utilisé comme courant std::lock_guard
, qui est utilisé lorsque vous avez besoin d'un pointeur brut). La convivialité serait hors de la porte.
Sans faire les choses biens meubles, une table serait nettement plus lent et moins évolutive que ce que vous avez l'habitude d'ailleurs.
La convivialité raisons (gestion des ressources) et des raisons d'efficacité (rapide, mobiliers allocations) hors de la voie, quoi d'autre GC est bon? Certainement pas à usage général. Entrez sans verrouillage des algorithmes.
Pourquoi sans verrouillage?
Sans verrouillage des algorithmes de travail en laissant une opération en vertu de la prétention d'aller temporairement "out of sync" avec la structure des données et la détection/correction lors d'une étape ultérieure. L'une des conséquences de cela est que, en vertu de la prétention de la mémoire peut être consulté après qu'il a été supprimé. Par exemple, si vous avez plusieurs threads concurrents de la pop un nœud à partir d'un PRINCIPE, il est possible pour un seul thread à la pop et de supprimer le nœud avant qu'un autre thread a réalisé le nœud était déjà pris:
Thread:
- Obtenir pointeur vers le nœud racine.
- Obtenir pointeur au prochain nœud du nœud racine.
- Suspendre
Le Fil B:
- Obtenir pointeur vers le nœud racine.
- Suspendre
Thread:
- Pop nœud. (remplacer le nœud racine pointeur avec nœud suivant pointeur, si le nœud racine pointeur n'a pas changé depuis qu'il a été lu.)
- Supprimer le nœud.
- Suspendre
Le Fil B:
- Obtenir pointeur au prochain nœud de notre pointeur de nœud racine, qui est maintenant "out of sync" et a été tout simplement supprimé et donc au lieu de nous bloquer.
À table, vous pouvez éviter la possibilité de lecture à partir de la mémoire non validées parce que le nœud ne sera jamais supprimé tandis que le Thread B est le référençant. Il y a des façons de contourner cela, comme le danger des pointeurs ou d'attraper SEH exceptions sur Windows, mais ceux-ci peuvent nuire à la performance de manière significative. GC a tendance à être la solution la plus optimale ici.