web-dev-qa-db-fra.com

Vous recherchez une classe de vecteur de type C ++ stl mais utilisez un stockage de pile

Avant d'écrire mon propre je vais vous demander tout y'all.

Je cherche une classe C++ qui ressemble presque exactement à un vecteur stl mais stocke des données dans un tableau sur la pile. Une sorte de classe d'allocator STL fonctionnerait également, mais j'essaie d'éviter tout type de tas, même des tas de threads alloués statiques (bien que l'un de ceux-ci est mon deuxième choix). La pile est juste plus efficace.

Il doit être presque une chute de remplacement du code actuel qui utilise un vecteur.

Pour ce que j'étais sur le point de m'écrire, je pensais à quelque chose comme ça:

char buffer[4096];
stack_vector<match_item> matches(buffer, sizeof(buffer));

Ou la classe pourrait avoir un espace tampon alloué en interne. Ensuite, ça ressemblerait à:

stack_vector<match_item, 256> matches;

Je pensais que cela lancerait STD :: Bad_ALLOC s'il manque d'espace, bien que cela ne se produise jamais.

Mise à jour

Utiliser Chrome Stack_Container.h fonctionne bien!

La raison pour laquelle je n'avais pas pensé de le faire de cette façon, c'est que j'ai toujours négligé le paramètre d'objet Allocator aux constructeurs de collecte STL. J'ai utilisé le paramètre Modèle à quelques reprises pour faire des piscines statiques, mais je n'ai jamais vu de code ni écrit qui a réellement utilisé le paramètre d'objet. J'ai appris quelque chose de nouveau. Très cool!

Le code est un peu désordonné et pour une raison quelconque GCC m'a forcé à déclarer l'allocator comme élément réel au lieu de la construire dans le paramètre d'allocator de vecteur. Ça va de quelque chose comme ça:

typedef std::pair< const char *, const char * > comp_list_item;
typedef std::vector< comp_list_item > comp_list_type;

comp_list_type match_list;
match_list.reserve(32);

Pour ça:

static const size_t comp_list_alloc_size = 128;
typedef std::pair< const char *, const char * > comp_list_item;
typedef StackAllocator< comp_list_item, comp_list_alloc_size > comp_list_alloc_type;
typedef std::vector< comp_list_item, comp_list_alloc_type > comp_list_type;

comp_list_alloc_type::Source match_list_buffer;
comp_list_alloc_type match_list_alloc( &match_list_buffer );
comp_list_type match_list( match_list_alloc );
match_list.reserve( comp_list_alloc_size );

Et je dois répéter que chaque fois que je déclare un nouveau. Mais ça marche comme je voulais.

J'ai remarqué que Stack_Container.h a un stackvector défini et j'ai essayé de l'utiliser. Mais cela n'hérite pas de vecteur ou de définir les mêmes méthodes, ce qui n'était donc pas un remplaçant. Je ne voulais pas réécrire tout le code en utilisant le vecteur pour que je puis je l'ai abandonné.

51
Zan Lynx

Vous n'êtes pas obligé d'écrire une classe de conteneurs complètement nouvelle. Vous pouvez coller avec vos conteneurs STL, mais changer le deuxième paramètre de par exemple std::vector Pour lui donner votre allocator personnalisé qui attribue à partir d'un tampon de pile. Les auteurs du chrome ont écrit un allocateur juste pour cela:

https://chromium.googlesource.com/chromium/chromium/+/master/base/stact_container.h

Cela fonctionne en allouant un tampon où vous dites à quel point c'est grand. Vous créez le conteneur et appelez container.reserve(buffer_size);. Si vous déborde de cette taille, l'allocator obtiendra automatiquement des éléments du tas (car il est dérivé de std::allocator, Il utilisera dans ce cas simplement les installations de l'allocator standard). Je n'ai pas essayé, mais cela ressemble à Google, je pense donc que ça vaut la peine d'essayer.

L'utilisation est comme ceci:

StackVector<int, 128> s;
s->Push_back(42); // overloaded operator->
s->Push_back(43);

// to get the real std::vector. 
StackVector<int, 128>::ContainerType & v = s.container();
std::cout << v[0] << " " << v[1] << std::endl;
41

Il semble que Boost :: static_vector est ce que vous cherchez. De la documentation:

static_vector est un hybride entre le vecteur et la matrice: comme vecteur, c'est un conteneur de séquence avec un stockage contigu qui peut changer de taille, ainsi que l'allocation statique, la hausse des frais généraux et la capacité fixe de la matrice. static_vector est basé sur Adam Wulkiewicz et Andrew Hundt de la classe Varray de Hundt de Hundt.

Le nombre d'éléments dans un statique_vecteur peut varier de manière dynamique à une capacité fixe car les éléments sont stockés dans l'objet lui-même de la même manière à un tableau.

16
Yury

Quelques options que vous voudrez peut-être regarder:

STLSOFT BY MATTHEW WILSON (auteur de l'imperfectant C++) a une classe de modèle auto_buffer qui place une matrice par défaut sur la pile, mais si elle augmente plus que l'attribution de la pile saisira la mémoire du tas. J'aime cette classe - si vous savez que vos tailles de conteneurs vont généralement être délimitées par une limite plutôt faible, vous obtenez la vitesse d'une matrice locale, pile allouée. Cependant, pour les cas d'angle où vous avez besoin de plus de mémoire, tout fonctionne toujours correctement.

http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html

Notez que la mise en œuvre que je m'utilise n'est pas STLSOFT, mais une mise en œuvre qui emprunte fortement.

"Le programmeur paresseux" a fait un poste pour une implémentation d'un conteneur utilisant alloca() pour le stockage. Je ne suis pas un fan de cette technique, mais je vous laisserai décider vous-même si c'est ce que vous voulez:

http://tlzprgmr.wordpress.com/2008/04/02/c-how-to-create-Variable-lengthearrays-on-the-stack/

Ensuite, il y a boost::array qui n'a aucun problème de dimensionnement dynamique des deux premiers, mais vous donne plus de l'interface vector que d'utiliser simplement des pointeurs comme itérateurs que vous obtenez avec des tableaux intégrés ( c'est-à-dire que vous obtenez begin(), end(), size(), etc.):

http://www.boost.org/doc/libs/1_37_0/doc/html/boost/array.html

11
Michael Burr

Vous pouvez utiliser votre propre allocator pour STD :: Vector et vous allez allouer des morceaux de votre stockage basé sur la pile, semblable à votre exemple. La classe d'allocator est la deuxième partie du modèle.

EDIT: Je n'ai jamais essayé cela et je regarde la documentation me conduit en outre à croire que vous ne pouvez pas écrire votre propre allocator. Je suis toujours en train de regarder.

4
Mark Ransom

tR1 :: Array correspond en partie à votre description. Il manque des choses comme Push ___ Retour (), etc., mais cela pourrait valoir la peine de regarder comme point de départ. Emballez-le et ajout d'un index au "Retour" pour supporter Push_back (), etc. Devrait être assez facile.

3
Boojum

Pourquoi voulez-vous le mettre sur le Stack en particulier? Si vous avez une implémentation d'Alloca (), vous pouvez boire un allocator de classe à l'aide de celle de MALLOC (), mais votre idée d'utiliser une matrice allouée statique est encore meilleure: il est tout aussi rapide sur la plupart des architectures, et vous ne le faites pas Risque Stack corruption de vous gâchez-vous.

2
Charlie Martin

C'est peut-être le cas que vous utilisez QT. Ensuite, vous voudrez peut-être aller pour QVarLengthArray ( docs ). Il se trouve fondamentalement entre std::vector et std::array, alloué de manière statique pour une certaine quantité et retomber à la répartition du tas si nécessaire.

Je préférerais la version de boost si je l'utilisais cependant.

2
Sebastian Graf

Boost a cela. Son appelé petit_vector

small_Vector est un conteneur ressemblant à un vecteur optimisé pour le cas lorsqu'il contient peu d'éléments. Il contient des éléments préélocalisés sur place, ce qui lui permet d'éviter l'utilisation d'une allocation de stockage dynamique lorsque le nombre réel d'éléments est inférieur à ce seuil préalloté. Small_Vector est inspiré par le Conteneur Smallvector de LLVM. Contrairement à Static_Vector, la capacité de Small_vector peut se développer au-delà de la capacité préallocée initiale.

small_Vector est convertible en petit_vector_base, un type indépendant du nombre d'éléments préallocalisés, ce qui permet au code du client qui n'a pas besoin d'être modélisé sur ce n argument. Small_Vecteur hérite de toutes les fonctions des membres du vecteur afin qu'il prend en charge toutes les fonctionnalités standard telles que l'emploi, les allocateurs d'état précis, etc.

1
fandyushin

Si vous souhaitez allouer sur la pile, mais vous ne voulez pas pré-définir une taille maximale au moment de la compilation, vous pouvez utiliser StackVector , une petite implémentation pouvant être utilisée comme suit:

new_stack_vector(Type, name, size)

Type est le type d'élément dans le vecteur, name est le nom de la variable du vecteur et size est le nombre maximal d'éléments pour permettre au vecteur.

size peut être variable et ne doit pas nécessairement être une constante de temps de compilation! : D

Exemple:

new_stack_vector(int, vec, 100); //like vector<int> vec; vec.reserve(100); but on the stack :)
vec.Push_back(10); //added "10" as the first item in the vector

...et c'est tout!

Disclaimer: N'utilisez jamais de très grandes tailles de matrices sur la pile en général. Comme vous ne devriez pas utiliser int var[9999999], Vous ne devriez pas utiliser la même chose new_stack_vector(int, vec, 9999999)! Utiliser de manière responsable.

0
MathuSum Mut