web-dev-qa-db-fra.com

Les éléments std :: vector sont-ils garantis contigus?

Ma question est simple: les éléments std :: vector sont-ils garantis contigus? Dans l'ordre de Word, puis-je utiliser le pointeur vers le premier élément d'un vecteur std :: comme un tableau C?

Si ma mémoire est bonne, le standard C++ n'a pas fait une telle garantie. Cependant, les exigences std :: vector étaient telles qu'il était pratiquement impossible de les satisfaire si les éléments n'étaient pas contigus.

Quelqu'un peut-il clarifier cela?

Exemple:

std::vector<int> values;
// ... fill up values

if( !values.empty() )
{
    int *array = &values[0];
    for( int i = 0; i < values.size(); ++i )
    {
        int v = array[i];
        // do something with 'v'
    }
}
100
Martin Cote

Cela a été omis de la norme C++ 98 proprement dite, mais ajouté plus tard dans le cadre d'un TR. La prochaine norme C++ 0x contiendra bien sûr cela comme une exigence.

Depuis n2798 (brouillon de C++ 0x):

23.2.6 Vecteur de modèle de classe [vecteur]

1 Un vecteur est un conteneur de séquence qui prend en charge les itérateurs à accès aléatoire. De plus, il prend en charge les opérations d'insertion et d'effacement à temps constant (amorties) à la fin; insérer et effacer au milieu prennent un temps linéaire. La gestion du stockage est gérée automatiquement, bien que des conseils puissent être donnés pour améliorer l'efficacité. Les éléments d'un vecteur sont stockés de manière contiguë, ce qui signifie que si v est un vecteur où T est un type autre que bool, alors il obéit à l'identité & v [n] == & v [0] + n pour tous 0 <= n <v .Taille().

103
dirkgently

Comme d'autres réponses l'ont souligné, le contenu d'un vecteur est garanti d'être continu (à l'exception de l'étrangeté de bool).

Le commentaire que je voulais ajouter est que si vous effectuez une insertion ou une suppression sur le vecteur, ce qui pourrait amener le vecteur à réaffecter sa mémoire, vous provoquerez l'invalidation de tous vos pointeurs et itérateurs enregistrés.

19
Bill Lynch

La norme garantit en effet qu'un vector est continu en mémoire et que &a[0] peut être passé à une fonction C qui attend un tableau.

L'exception à cette règle est vector<bool> qui n'utilise qu'un bit par bool donc bien qu'il ait une mémoire continue, il ne peut pas être utilisé comme bool* (ceci est largement considéré comme une fausse optimisation et une erreur).

BTW, pourquoi n'utilisez-vous pas d'itérateurs? C'est pour ça qu'ils sont.

7
Motti

Comme d'autres l'ont déjà dit, vector utilise en interne un tableau contigu d'objets. Les pointeurs dans ce tableau doivent être traités comme invalides chaque fois qu'une fonction non-membre membre est appelée IIRC.

Cependant, il existe une exception!!

vector<bool> a une implémentation spécialisée conçue pour économiser de l'espace, de sorte que chaque booléen n'utilise qu'un seul bit. Le tableau sous-jacent n'est pas un tableau contigu de bool et d'arithmétique de tableau sur vector<bool> ne fonctionne pas comme vector<T> aurait.

(Je suppose qu'il est également possible que cela soit vrai pour toute spécialisation de vecteur, car nous pouvons toujours en implémenter un nouveau. Cependant, std::vector<bool> est la seule spécialisation standard, err, sur laquelle l'arithmétique de pointeur simple ne fonctionnera pas.)

5
Wuggy

J'ai trouvé ce fil parce que j'ai un cas d'utilisation où les vecteurs utilisant une mémoire contiguë sont un avantage.

J'apprends à utiliser des objets de tampon de sommet dans OpenGL. J'ai créé une classe wrapper pour contenir la logique du tampon, donc tout ce que je dois faire est de passer un tableau de flottants et quelques valeurs de configuration pour créer le tampon. Je veux pouvoir générer un tampon à partir d'une fonction basée sur l'entrée utilisateur, donc la longueur n'est pas connue au moment de la compilation. Faire quelque chose comme ça serait la solution la plus simple:

void generate(std::vector<float> v)
{
  float f = generate_next_float();
  v.Push_back(f);
}

Maintenant, je peux passer les flotteurs du vecteur sous forme de tableau aux fonctions liées au tampon d'OpenGL. Cela supprime également la nécessité de sizeof pour déterminer la longueur de la matrice.

C'est bien mieux que d'allouer un tableau énorme pour stocker les flotteurs et en espérant que je l'ai fait assez grand, ou de créer mon propre tableau dynamique avec un stockage contigu.

3
NobodyImportant

Oui, les éléments d'un vecteur std :: sont garantis contigus.

2
Benoît

cplusplus.com:

Les conteneurs vectoriels sont implémentés sous forme de tableaux dynamiques; Tout comme les tableaux ordinaires, les conteneurs vectoriels ont leurs éléments stockés dans des emplacements de stockage contigus, ce qui signifie que leurs éléments sont accessibles non seulement à l'aide d'itérateurs mais également à l'aide de décalages sur des pointeurs réguliers vers des éléments.

1
Igor Oks