Quel est l'avantage d'utiliser std::allocator au lieu de new en C++?

je viens de lire à propos de std::allocator . À mon avis, il est plus compliqué de l'utiliser au lieu d'utiliser new et delete .

avec allocator nous devons explicitement allouer la mémoire en tas, la construire, la détruire, puis finalement désallouer la mémoire. Alors pourquoi était-il créé?

dans quels cas peut-il être utilisé et quand doit-il être utilisé au lieu de nouveau et supprimer?

54
demandé sur Peter Mortensen 2015-07-11 18:36:06

7 réponses

std::allocator est l'allocateur de mémoire par défaut pour les conteneurs de bibliothèque standard, et vous pouvez remplacer vos propres allocateurs. Cela vous permet de contrôler comment les conteneurs standard allouer la mémoire. Mais je ne pense pas que votre question porte spécifiquement sur std::allocator , mais plutôt sur la stratégie d'allouer la mémoire, puis de construire des objets dans cette mémoire, plutôt que d'utiliser new T[N] , par exemple.

Et la raison en est que new T[N] ne vous permet pas de contrôler ce que les constructeurs sont appelés. Et il vous oblige à construire tous vos objets en même temps. C'est terrible pour les fins de, par exemple, std::vector où vous ne voulez allouer que de temps en temps.

avec un allocateur de mémoire brut, vous pouvez allouer une certaine quantité de mémoire, qui détermine votre capacité. Ensuite, comme l'utilisateur ajoute des éléments au vecteur (en utilisant le constructeur de son choix), vous pouvez construire des objets en place dans ce mémoire.

puis quand vous manquez de mémoire, vous allouer plus, généralement deux fois plus. Si std::vector utilisé new T[N] , il faudrait réaffecter chaque fois que vous voulez ajouter ou supprimer un élément, ce qui serait terrible pour la performance. Vous seriez également forcé d'utiliser le constructeur par défaut pour tous les objets, ce qui met une restriction inutile sur les types d'objets std::vector peut tenir.

39
répondu Benjamin Lindley 2015-07-12 18:39:06

à mon avis, il est plus compliqué de l'utiliser au lieu d'utiliser new et delete.

Oui , mais il n'est pas destiné à remplacer new et delete , il sert un but différent.

avec allocator nous devons explicitement allouer la mémoire de tas, la construire, la détruire, et finalement désallouer la mémoire.

alors pourquoi a-t-il été créé?

parce que parfois vous voulez séparer l'attribution et la construction en deux étapes (et de la même façon séparer la destruction et la désallocation en deux étapes). Si vous ne voulez pas faire cela, n'utilisez pas d'allocateur, utilisez new à la place.

dans quels cas peut-il être utilisé et quand doit-il être utilisé au lieu de nouveau et supprimer?

quand vous avez besoin du comportement d'un allocateur, pas le comportement de new et delete , évidemment! Le cas typique est lors de la mise en œuvre d'un conteneur.

considérons le code suivant:

std::vector<X> v;
v.reserve(4);        // (1)
v.push_back( X{} );  // (2)
v.push_back( X{} );  // (3)
v.clear();           // (4)

ici la ligne (1) doit allouer assez de mémoire pour quatre objets, mais ne pas les construire encore. Ensuite, les lignes (2) et (3) doivent construire des objets dans la mémoire allouée. Alors line (4) doit détruire ces objets, mais ne pas désallouer la mémoire. Enfin, dans le destructeur du vecteur, toute la mémoire peut être libéré.

ainsi, le vecteur ne peut pas simplement utiliser new X() ou delete &m_data[1] pour créer et détruire les objets, il doit effectuer l'allocation/désallocation séparément de la construction/destruction. L'argument template allocator d'un conteneur définit la politique qui doit être utilisée pour (de)allouer la mémoire et construire/détruire des objets, permettant de personnaliser l'utilisation de la mémoire par le conteneur. La politique par défaut est le type std::allocator .

Si vous utilisez un allocateur lorsqu'un allocateur est requise (comme lors de l'utilisation d'un conteneur) et que vous utilisez std::allocator quand vous ne voulez pas fournir un allocateur personnalisé et vous voulez juste le standard.

vous n'utilisez pas un allocateur pour remplacer new et delete .

45
répondu Jonathan Wakely 2015-07-12 18:44:50

Allocateurs sont un concept très important dans la STL. Chaque conteneur est capable de prendre un allocator comme argument. Les attributions seront alors effectuées à l'aide de ce répartiteur, et non du répartiteur standard.

ceci est utile par exemple pour allouer des objets de la même taille dans un pool, pour améliorer les performances, ou pourrait être nécessaire s'il y a une zone spéciale de mémoire où vos objets ont besoin de vivre.

les étapes de l'attribution et de la construction sont séparé parce que par exemple pour vecteur ( std::vector::reserve ) il est important de pouvoir allouer de la mémoire pour une utilisation future, mais pas (encore) créer des objets.

comme un exemple vous pouvez écrire un allocator comme une classe, contenant un tableau de taille fixe, et utiliser ce tableau pour fournir de la mémoire pour un conteneur standard. Alors vous pouvez avoir une instance de cette classe sur la pile et ainsi éviter complètement les allocations de tas pour une partie votre programm.

Voir plus d'exemples ici dans ce message.

[...] quand doit-il être utilisé [...]

lorsque vous avez des besoins spécifiques, et plus important lorsque vous écrivez vos propres conteneurs génériques.

8
répondu Daniel Jour 2017-05-23 11:47:25

votre instinct est juste. Dans 90% des cas, utilisez new . Cependant, l'avis dans les structures comme, par exemple, le carte structure de données. Un de ses arguments de modèle par défaut est class Alloc = allocator<pair<const Key,T> , qui définit comment la classe crée de nouvelles instances de choses et gère les instances existantes. De cette façon, vous pourriez théoriquement créer votre propre allocator et l'utiliser ensuite pour les structures de données existantes. Puisque new et delete sont des fonctions et non des classes, il est nécessaire d'avoir le std::allocator pour les représenter et leur faire des arguments de modèle valides.

6
répondu Silvio Mayolo 2015-07-11 15:48:50

le std::allocator a été créé pour permettre aux développeurs plus de contrôle de la façon dont la mémoire est attribuée. Dans de nombreux systèmes embarqués, la mémoire est limitée et dans différents types. Il peut ne pas être une somme énorme. En outre, l'allocation de mémoire veut être minimisée pour éviter les problèmes de fragmentation.

L'allocateur permet également l'attribution de différents pools de mémoire. Ainsi, par exemple, allouer des blocs de petite taille serait plus efficace à partir d'un petit bloc de mémoire.

5
répondu Thomas Matthews 2015-07-11 15:46:04

new et delete sont la voie la plus directe pour créer un objet dans la dynamique de la mémoire et de l'initialiser. Allocateurs sont beaucoup plus, parce qu'ils offrent un contrôle complet sur ladite phases.

avec allocator nous devons explicitement allouer la mémoire tas, la construire, détruisez-le, et puis désallocez la mémoire.

en effet, les allocateurs ne sont pas censés être utilisés pour le code "normal" où new et delete seraient également amende. Considérez une classe comme std::map , souvent implémentée comme un arbre: avez-vous besoin de désallouer la feuille entière chaque fois qu'un objet tenu est supprimé? Les allocateurs vous permettent de détruire cet objet, mais gardez la mémoire pour que vous n'ayez pas à l'exiger à nouveau.

en outre, vous pouvez spécialiser un allocateur pour un certain type si vous connaissez des méthodes plus optimisées pour son contrôle qui n'est pas possible pour new et delete .

4
répondu edmz 2015-07-11 16:03:05

la raison de ce STL membre est de donner au développeur plus de contrôle sur la mémoire. Ce que j'entends par là, par exemple, c'est que le nouvel opérateur n'est pas vraiment une opération en soi. À la base, il effectue une réservation de mémoire ET puis remplit l'espace avec l'objet.

bien que je ne puisse pas sur ma tête trouver un cas spécifique, scénario du monde réel, vous devriez utiliser std::allocator et tel Lorsque, peut-être, la destruction d'un objet donné peut avoir un impact sur d'autres objets en mémoire.

disons, pour le bien de l'argument, vous avez créé une sorte de vecteur dont chaque élément est double-lié à un autre objet dans la mémoire et vous voulez, au moment de la suppression de ce vecteur, les objets liés pour supprimer la référence de retour à elle.

4
répondu Anzurio 2015-07-12 18:40:23