2010-07-28 3 views
4

J'ai un std :: vecteur de valeurs pour lesquelles je connais la taille maximale, mais la taille réelle variera pendant l'utilisation:Comment puis-je obtenir l'adresse du buffer allouée par vector :: reserve()?

void setupBuffer(const size_t maxSize) { 
    myVector.reserve(maxSize); 
} 

void addToBuffer(const Value& v) { 
    myVector.push_back(v); 

    if (myVector.size() == maxSize) { 
    // process data... 
    myVector.clear(); 
    } 
} 

Cependant, setupBuffer, je dois obtenir un pointeur vers le début de Les données de myVector. J'utilise une bibliothèque tierce dans laquelle je dois mettre en cache ce pointeur avant de l'utiliser dans un appel effectué pendant la section "données de processus ...".

void setupBuffer(const size_t maxSize) { 
    myVector.reserve(maxSize); 

    cachePtr(&(myVector[0])); // doesn't work, obviously 
} 

Je ne veux pas redimensionner() le vecteur avant, comme je veux utiliser vector.size() pour signifier le nombre d'éléments ajoutés au vecteur.

Donc, est-il possible d'obtenir le pointeur sur le tampon du vecteur après l'allocation (reserve()) mais avant qu'il ait des éléments? J'imagine que le tampon existe (et ne bougera pas tant que je limiterai le nombre de valeurs push_back'd) .... peut-être que ce n'est pas garanti?

+2

Pourquoi avez-vous besoin de mettre en cache le pointeur, plutôt que de le lire en toute sécurité lorsque vous en avez besoin? –

+0

J'utilise une bibliothèque tierce pour les E/S dans un format de fichier spécifique. La façon dont cela fonctionne est de mettre en place des «tampons» dans la bibliothèque en envoyant un pointeur et une taille maximale. Vous pouvez ensuite appeler de manière asynchrone par ex. 'write' qui vide les données sur le disque. Je pourrais mettre en place le pointeur à chaque fois que je toucherais maxSize, mais ce serait un surcoût supplémentaire (combien je devrais tester). Bon point, cependant. – Ryan

+0

Notez que cette question vous demande comment obtenir le pointeur, mais les réponses diffèrent sur ce que vous êtes autorisé à * faire * avec ce pointeur une fois que vous l'avez. Pour une question qui couvre directement ce problème, veuillez consulter [Le pointeur brut est-il accessible après std :: vector :: reserve safe?] (Http://stackoverflow.com/questions/8228072/is-accessing-the-raw-pointer -after-stdvectorreserve-safe) –

Répondre

4

Le tampon vectoriel ne sera pas déplacé après un appel à réserver, sauf si vous dépassez la capacité réservée. Votre problème est d'obtenir le pointeur sur le premier élément. La réponse évidente est de pousser une seule fausse entrée dans le vecteur, d'obtenir le pointeur dessus, puis de l'enlever. Une meilleure approche serait si la bibliothèque acceptait un foncteur plutôt qu'un pointeur, qu'elle appellerait quand elle avait besoin d'accéder au tampon - vous pourriez faire en sorte que le foncteur obtienne l'adresse jusqu'à ce que le tampon ait du vrai contenu. Cependant, je réalise que vous n'avez pas le luxe de réécrire la bibliothèque.

+0

Oui, c'est ce que je fais. Merci. – Ryan

+0

Bonne idée, '+ 1' de moi. Je suppose que techniquement c'est toujours un comportement indéfini, mais en pratique cela fonctionnera probablement avec chaque implémentation. – sbi

+1

@sbi Je ne vois pas pourquoi ce serait UB - une référence? –

2

Non. Vous n'êtes pas autorisé à accéder à un élément dans le fector avec un index supérieur à size. Resize est votre seule option ici.

Qu'est-ce que vous pouvez faire est quelque chose comme:

myvec.resize(SOME_LARGE_VALUE); 
myLibrary(&myVec[0]); 
myvec.resize(GetSizeUsedByLibrary()); 

Lorsque vous redimensionnez, les éléments du vecteur ne sont pas détruits, sauf ceux qui avaient un indice au-dessus de la nouvelle taille. Les éléments situés sous le nombre défini dans le redimensionnement sont laissés à eux-mêmes. Example using std::basic_string, but equally applicable to vector

+0

Oui, c'est ce que je suis en train de faire: myVector.reserve (maxSize); myVector.resize (1); cachePtr (& myVector [0]); myVector.clear(); Semble fonctionner. J'espérais juste qu'il y avait une façon plus propre. Merci. – Ryan

+0

@Ryan: Ceci est invalide. Vraisemblablement l'API C 'cachePtr' accède au premier élément du vecteur, ce qui signifie que vous avez un comportement indéfini. Pour un comportement valide, vous devez rester au-dessous de 'size()', pas de 'capacity()'. Cela peut sembler fonctionner; mais une réponse valide pour un comportement indéfini est "semble fonctionner". –

-1

Il y a beaucoup de hacks autour. Mais je vous recommande de façon valable - dérogation allocateur, le second argument de modèle:

typedef std::vector<MyItem, MyAllocator> myvector_t; 

Après en MyAllocator fournir fixe l'allocation de mémoire tampon, et de transmettre cette instance allocateur comme arguemnt du constructeur de vecteur

+0

-1 pour un comportement indéfini. Le vecteur va par défaut construire des éléments quand il est redimensionné, ce qui détruira le contenu au-dessus de l'ancienne taille du vecteur, même avec l'allocateur. –

+0

Suggestion intéressante, mais l'allocation n'est pas vraiment le problème. C'est plus une question d'API sur la façon de sortir le pointeur de std :: vector ... pas sûr qu'un allocateur personnalisé aiderait w/that. – Ryan

+0

@Billy ONeal - NON, si la taille est bien connue, alors vous devriez allouer le tampon une fois - au constructeur de l'allocateur. Après réallocation doit être empêché (par exemple par assertion). Toute allocation doit être effectuée dans le tampon initial de l'allocateur. – Dewfy

0

Avez-vous essayé avant ()? En outre, vous pouvez repousser un élément, obtenir l'adresse comme vous l'avez fait, puis l'effacer.

Tout cela n'est pas garanti, mais vous pouvez lire la source de votre vecteur <> pour voir si cela vous convient si vous devez le faire. Vous pouvez également rouler votre propre vecteur assez facilement avec un pointeur sur les données et ne les déplace jamais.

+2

Vous ne savez pas comment front() est différent de [0] dans vector, au moins sur la base de la documentation. Comme il renvoie une référence, il devrait avoir au moins un objet construit. – Ryan

+0

Je suppose que je pensais que la réserve l'avait créée et [0] se plaignait de l'accès à un élément qui n'existe pas. Je me demandais si front() vérifiait les limites (les docs que je regardais ne disaient pas). Vous pourriez ajouter et effacer un élément. –