STL avec des vecteurs non initialisé de stockage?
Je suis en train d'écrire une boucle interne qui doit struct
s de stockage contigu. Je ne sais pas combien de ces struct
s il y aura à l'avance. Mon problème est que STL vector
initialise ses valeurs à 0, alors peu importe ce que je fais, j'assume le coût de l'initialisation, plus le coût de la mise à l' struct
's les membres de leurs valeurs.
Est-il un moyen pour empêcher l'initialisation, ou est-il un STL-comme conteneur avec redimensionnables de stockage contigu et non initialisée éléments?
(Je suis certain que cette partie du code qui doit être optimisé, et je suis certain que l'initialisation est un coût important.)
Aussi, voir mes commentaires ci-dessous pour une clarification au sujet lors de l'initialisation se produit.
CODE:
void GetsCalledALot(int* data1, int* data2, int count) {
int mvSize = memberVector.size()
memberVector.resize(mvSize + count); //causes 0-initialization
for (int i = 0; i < count; ++i) {
memberVector[mvSize + i].d1 = data1[i];
memberVector[mvSize + i].d2 = data2[i];
}
}
- Note - l'utilisation de la réserve() n'est pas une solution, puisque vous ne pouvez pas légalement accès aux données à des endroits end() et ci-dessus.
- Une autre précision: ce n'est pas que le constructeur initialise les valeurs à 0. C'est qui redimensionne les appels d'insertion, qui ne.
- Pourriez-vous nous donner la structure de la déclaration, trop? Merci... 🙂
- REMARQUE: vous ne pouvez pas accéder à des données non initialisées de toute façon. Même question pour vector<T> le passé .fin() et non initialisée membres d'un T[]. Mais avec un vecteur, les chances sont le débogage de code vous dit que maintenant. Le tableau de code échoue silencieusement sur les clients PC.
- C'est une bonne question. Pour certaines applications, il est important de réaliser que std::vector initialise toujours ses éléments, même s'ils sont de plain-vieux-données (POD).
- Voir aussi stackoverflow.com/q/7218574/1969455 pour un allocateur de l'approche. (bon pour les POD types)
Vous devez vous connecter pour publier un commentaire.
std::vector
doit initialiser les valeurs dans le tableau en quelque sorte, ce qui signifie que certaines constructeur (ou le constructeur par copie) doit être appelée. Le comportement devector
(ou n'importe quel conteneur de classe) n'est pas défini si vous étiez à accéder à la non initialisée section de la matrice comme si il ont été initialisés.Le meilleur moyen est d'utiliser
reserve()
etpush_back()
, de sorte que le constructeur par copie est utilisée, évitant par défaut-de la construction.À l'aide de votre code d'exemple:
Le seul problème avec l'appel de
reserve()
(ouresize()
), comme cela est que vous pouvez vous retrouver en invoquant le constructeur par copie plus souvent que vous en avez besoin. Si vous pouvez faire une bonne prédiction de la taille finale de la matrice, il est préférable dereserve()
l'espace une fois au début. Si vous ne connaissez pas la taille finale, même si, à moins que le nombre de copies sera minime en moyenne.Dans la version actuelle de C++, la boucle interne est un peu inefficace comme une valeur temporaire est construit sur la pile, et le copier-construit les vecteurs de la mémoire, et enfin, le temporaire est détruit. Toutefois, la prochaine version de C++ dispose d'une fonction appelée R-Valeur de références (
T&&
) qui permettra.L'interface fournie par
std::vector
ne permet pas pour une autre option, qui consiste à utiliser une partie d'usine-comme la classe, de construire d'autres valeurs que la valeur par défaut. Voici un exemple grossier de ce que ce modèle serait comme implémenté en C++:Faire cela signifie que vous devez créer votre propre classe vector. Dans ce cas, il complique aussi ce qui devrait être un exemple simple. Mais il peut y avoir des moments où l'utilisation d'une fonction de fabrication comme c'est mieux, par exemple si l'insertion est subordonnée à une autre valeur, et que vous auriez autrement sans condition de construire une cher temporaire, même si elle n'était pas réellement nécessaire.
C++0x ajoute une nouvelle fonction membre template
emplace_back
àvector
(qui s'appuie sur les variadic templates et de transfert parfait) qui se débarrasse de toute temporaires entièrement:De préciser dans la réserve (les) réponses: vous avez besoin d'utiliser la réserve de() en collaboration avec push_back(). De cette façon, le constructeur par défaut n'est pas appelée pour chaque élément, mais plutôt le constructeur de copie. Vous encourir la peine de la configuration de votre structure sur la pile, puis de le copier dans le vecteur. D'autre part, il est possible que si vous utilisez
le compilateur va construire la nouvelle instance directement dans la mémoire thatbelongs pour le vecteur. Cela dépend de la façon intelligente l'optimiseur. Vous devez vérifier le code généré pour le savoir.
En C++11 (et boost), vous pouvez utiliser le tableau de la version de
unique_ptr
pour allouer un tableau non initialisé. Ce n'est pas tout à fait un conteneur stl, mais il est encore la mémoire gérés et C++-ish qui sera bien suffisant pour de nombreuses applications.Alors, voici le problème, resize est l'appel insérer, ce qui est en train de faire une copie de la construction d'un défaut d'élément construit pour chacun des nouveaux éléments ajoutés. Pour obtenir ce à 0 coût, vous devez écrire votre propre constructeur par défaut ET votre propre constructeur de copie de vider ces fonctions. Le faire à votre constructeur de copie est un très mauvaise idée parce que ça va casser std::vector de la réaffectation interne des algorithmes.
Résumé: Vous n'allez pas être en mesure de le faire avec std::vector.
Euh...
essayer la méthode:
Il vous permettra de réserver de la mémoire pour les éléments x sans l'initialiser tout (vecteur est toujours vide). Ainsi, il n'y aura pas de réaffectation jusqu'à aller au-dessus de x.
Le deuxième point est que le vecteur de ne pas initialiser les valeurs à zéro. Êtes-vous de tester votre code en debug ?
Après vérification sur g++, le code suivant:
donne les résultats suivants:
L'initialisation que vous avez vu était probablement un artefact.
[EDIT] Après le commentaire sur redimensionner, j'ai modifié le code pour ajouter les redimensionner ligne. Le redimensionnement efficacement appelle le constructeur par défaut de l'objet à l'intérieur du vecteur, mais si le constructeur par défaut ne fait rien, alors rien n'est initialisé... je crois toujours que c'était un artefact (j'ai réussi la première fois que l'ensemble de l'vecteur zerooed avec le code suivant:
Donc...
:-/
[EDIT 2] Comme déjà offerts par d'Arkadi, la solution est d'utiliser une ligne constructeur prenant les paramètres désirés. Quelque chose comme
Ce sera probablement incorporé dans votre code.
Mais tu devrais tout de même de l'étude de votre code avec un profiler pour être sûr que ce morceau de code est le goulot d'étranglement de votre application.
Utiliser les std::vector::reserve() la méthode. Il n'est pas redimensionné le vecteur, mais il va allouer de l'espace.
De vos commentaires à d'autres affiches, on dirait que vous êtes de gauche avec malloc() et ses amis. Vecteur de ne pas vous laisser avoir unconstructed éléments.
À partir de votre code, il semble que vous avez un vecteur de structures comprenant chacune 2 ints. Pourriez-vous, au lieu d'utiliser 2 vecteurs d'entiers? Puis
Maintenant, vous n'avez pas à payer pour la copie d'un struct chaque fois.
Si vraiment vous insistez pour avoir les éléments non initialisée et le sacrifice de certaines méthodes comme avant(), back(), push_back(), utilisez le boost vecteur de numérique . Il vous permet même de ne pas conserver les éléments existants lors de l'appel de redimensionnement()...
Vous pouvez utiliser un wrapper type autour de votre type d'élément, avec un constructeur par défaut qui ne fait rien. E. g.:
À utiliser:
Ne les structures elles-mêmes doivent être contigu de mémoire, ou pouvez-vous sortir avec un vecteur de struct*?
Vecteurs de faire une copie de tout ce que vous ajoutez à eux, donc, à l'aide de vecteurs de pointeurs plutôt que des objets est un moyen pour améliorer les performances.
Je ne pense pas que la STL est votre réponse. Vous allez avoir besoin pour restaurer votre propre solution à l'aide de realloc(). Vous aurez pour stocker un pointeur, et la taille, ou le nombre d'éléments, et de l'utiliser pour trouver l'endroit où commencer à ajouter des éléments après un realloc().
Je ferais quelque chose comme:
Vous avez besoin de définir un ctor pour le type qui est stocké dans le memberVector, mais c'est un faible coût, car il vous donnera le meilleur des deux mondes; pas inutile d'initialisation est faite et il ne réaffectation va se produire au cours de la boucle.