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 de tas, la construire, la détruire et enfin libérer la mémoire. Alors pourquoi a-t-il été créé?

Dans quels cas peut-il être utilisé et quand devrait-il être utilisé à la place de nouveau et supprimer?

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 la façon dont les conteneurs standard allouent de la mémoire. Mais je ne pense pas que votre question concerne spécifiquement std::allocator , mais plutôt la stratégie d’allocation de mémoire, puis la construction d’objects dans cette mémoire, plutôt que l’utilisation de new T[N] , par exemple.

Et la raison en est que le new T[N] ne vous permet pas de contrôler quels constructeurs sont appelés. Et cela vous oblige à construire tous vos objects en même temps. C’est terrible pour, par exemple, std::vector où vous voulez seulement allouer occasionnellement.

Avec un allocateur de mémoire brute, vous pouvez allouer une certaine quantité de mémoire, ce qui détermine votre capacité. Ensuite, lorsque l’utilisateur ajoute des éléments au vecteur (en utilisant le constructeur de son choix), vous pouvez construire des objects en place dans cette mémoire.

Ensuite, lorsque vous manquez de mémoire, vous allouez plus, généralement deux fois plus. Si std::vector utilisait le new T[N] , il devrait réallouer chaque fois que vous souhaitiez append ou supprimer un élément, ce qui serait terrible pour les performances. Vous seriez également obligé d’utiliser le constructeur par défaut pour tous les objects, ce qui crée une ressortingction inutile sur les types d’objects que std::vector peut contenir.

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

Oui, mais il n’est pas destiné à remplacer le new et le delete , il sert un objective différent.

Avec allocator, nous devons explicitement allouer la mémoire de tas, la construire, la détruire et enfin libérer la mémoire.

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

Parce que parfois vous voulez séparer l’allocation et la construction en deux étapes (et de la même manière, séparer la destruction et la désallocation en deux étapes). Si vous ne voulez pas faire cela, n’utilisez pas d’allocateur, utilisez plutôt new .

Dans quels cas peut-il être utilisé et quand devrait-il être utilisé à la place de nouveau et supprimer?

Lorsque vous avez besoin du comportement d’un allocateur, pas du comportement de new et delete , évidemment! Le cas typique est lors de l’implémentation d’un conteneur.

Considérez le code suivant:

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

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

Ainsi, le vecteur ne peut pas simplement utiliser new X() ou delete &m_data[1] pour créer et détruire les objects, il doit effectuer une allocation / désallocation séparément de la construction / destruction. L’argument de modèle d’allocateur d’un conteneur définit la stratégie à utiliser pour (dé) allouer de la mémoire et pour construire / détruire des objects, ce qui permet de personnaliser l’utilisation de la mémoire par le conteneur. La politique par défaut est le type std::allocator .

Vous utilisez donc un allocateur lorsqu’un allocateur est requirejs (par exemple lors de l’utilisation d’un conteneur) et vous utilisez std::allocator lorsque vous ne voulez pas fournir d’allocateur personnalisé et que vous souhaitez simplement utiliser un allocateur standard.

Vous n’utilisez pas d’allocateur en remplacement de new et delete .

Les allocateurs sont un concept très important dans le TSL. Chaque conteneur est capable de prendre un allocateur comme argument. Ensuite, les allocations seront effectuées à l’aide de cet allocateur et non de celui standard.

Ceci est utile, par exemple, pour allouer des objects de même taille dans un pool, pour améliorer les performances, ou peut être nécessaire s’il existe une zone de mémoire spéciale dans laquelle vos objects doivent vivre.

Les étapes d’allocation et de construction sont séparées car, par exemple, pour vector ( std::vector::reserve ), il est important de pouvoir allouer de la mémoire pour une utilisation future, mais pas (encore) d’y créer des objects.

Par exemple, vous pourriez écrire un allocateur en tant que classe, contenant un tableau de taille fixe, et utiliser ce tableau pour fournir de la mémoire à certains conteneurs standard. Ensuite, vous pouvez avoir une instance de cette classe sur la stack et ainsi éviter complètement les allocations de tas pour une partie de votre programme.

Voir plus d’exemples ici dans ce post SO.

[…] quand devrait-il être utilisé […]

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

Votre instinct a raison. Dans 90% des cas, utilisez new . Cependant, notez dans les structures comme, par exemple, la structure des données cartographiques . L’un de ses arguments par défaut est la class Alloc = allocator , qui définit comment la classe crée de nouvelles instances de choses et gère les instances existantes. De cette façon, vous pouvez théoriquement créer votre propre allocateur 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 std::allocator pour les représenter et en faire des arguments de template valides.

std::allocator été créé pour permettre aux développeurs de mieux contrôler la manière dont la mémoire est allouée. Dans de nombreux systèmes embarqués, la mémoire est contrainte et de différents types. Il n’y en a peut-être pas beaucoup. En outre, l’allocation de mémoire doit être minimisée pour éviter les problèmes de fragmentation.

L’allocateur permet également une allocation à partir de différents pools de mémoire. Ainsi, par exemple, l’allocation de blocs de petite taille serait plus efficace dans un pool de mémoire de petit bloc.

new et delete sont le moyen direct de créer un object en mémoire dynamic et de l’initialiser. Les allocateurs sont beaucoup plus nombreux, car ils offrent un contrôle complet sur les phases susmentionnées.

Avec allocator, nous devons explicitement allouer la mémoire de tas, la construire, la détruire et enfin libérer la mémoire.

En effet, les allocateurs ne sont pas supposés être utilisés pour un code “normal” où new et delete seraient également corrects. Considérons une classe comme std::map , souvent implémentée sous la forme d’un arbre: avez-vous besoin de désallouer la feuille entière lorsqu’un object est supprimé? Les allocators vous permettent de détruire cet object, mais gardez la mémoire pour que vous n’ayez plus à l’exiger.

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

La raison de ce membre STL est de donner au développeur plus de contrôle sur la mémoire. Ce que je veux dire par là, par exemple, le nouvel opérateur n’est pas vraiment une opération en soi. À la base, il effectue une réservation de mémoire ET remplit ensuite cet espace avec l’object.

Bien que je ne puisse pas imaginer un scénario concret, vous devriez utiliser std::allocator , par exemple lorsque la destruction d’un object donné pourrait avoir un impact sur d’autres objects en mémoire.

Disons, pour des raisons d’argument, que vous avez créé une sorte de vecteur dont chaque élément est lié à un autre object en mémoire et que vous voulez, lors de la suppression dudit vecteur, les objects liés pour supprimer la référence à il.