Bonjour,
Dans mon programme, j'ai besoin d'avoir un espace contigue de string et pour
cela je fais :
std::vector<string> MesStrings;
MesString.reserve(1000); // <= Si je reserve pas, l'espace n'est
pas contigue et a chaque ajout il me change les adresses
// et dans mon prog il
me faut des adresses qui ne changent pas a chaque ajout
// J'ajoute kk string
for (int i=0;i<100;i++)
{
string temp = "toto";
MesString.push-back(temp);
}
Ensuite, pour désallouer l'espace je fais :
MesString.clear();
Mon compilateur (vc++) me dit que j'ai des fuites. J'ai noté que si je ne
reserve pas d'espace au debut, je n'ai pas ces memory-leak.
Quelqu'un peut-il m'expliquer le pourquoi du comment ???
Merci !
--
---------------------------------------------------------------------------
Envie de déco ? http://www.decoetalage.net
Une petite question en passant... Si pendant l'execution du prog on se rend compte que le reserve initial etait trop juste, y-a-til une maniere d'allouer plus d'espace en gardant la mémoire contigue ? (enfin, disons en "forcant" l'allocation a etre contigue; quitte a emmettre un message d'erreur, ou ajuster e programme si cela n'a pas été possible)
Autant que je sache, la mémoire utilisée par vector est toujours contiguë. Si ce n'est pas garanti par la norme actuelle, il me semble que ça le sera dans la prochaine norme. En attendant, tous les compilateurs que je connais (re-)allouent toujours un bloc de mémoire contiguë pour vector.
Bonjour,
Une petite question en passant... Si pendant l'execution du prog on se rend
compte que le reserve initial etait trop juste, y-a-til une maniere
d'allouer plus d'espace en gardant la mémoire contigue ? (enfin, disons en
"forcant" l'allocation a etre contigue; quitte a emmettre un message
d'erreur, ou ajuster e programme si cela n'a pas été possible)
Autant que je sache, la mémoire utilisée par vector est toujours
contiguë. Si ce n'est pas garanti par la norme actuelle, il me semble
que ça le sera dans la prochaine norme. En attendant, tous les
compilateurs que je connais (re-)allouent toujours un bloc de mémoire
contiguë pour vector.
Une petite question en passant... Si pendant l'execution du prog on se rend compte que le reserve initial etait trop juste, y-a-til une maniere d'allouer plus d'espace en gardant la mémoire contigue ? (enfin, disons en "forcant" l'allocation a etre contigue; quitte a emmettre un message d'erreur, ou ajuster e programme si cela n'a pas été possible)
Autant que je sache, la mémoire utilisée par vector est toujours contiguë. Si ce n'est pas garanti par la norme actuelle, il me semble que ça le sera dans la prochaine norme. En attendant, tous les compilateurs que je connais (re-)allouent toujours un bloc de mémoire contiguë pour vector.
kanze
Fabien LE LEZ wrote:
On Mon, 7 Feb 2005 23:16:49 +0100, "Alex" :
MesString.reserve(1000);
- Il me semble que reserve() peut être une no-op (quelqu'un peut confirmer ?)
Il est même garanti être un no-op si capacity() vaut plus que son paramètre. Alors, dans une implémentation où le constructeur initialise le vector avec max_size() capacité systèmatiquement. (Mais évidemment, je parle des implémentations qu'on ne vera jamais, parce qu'inutilisable.)
La norme garantit qu'après reserve, capacity() serait au moins aussi grande que le paramètre de reserve(). Elle garantie aussi que tant que la taille reste inférieur à cette capacité, les pointeurs, les références et les itérateurs vers le vecteur resteront valide. (En fait, ce qui importe, ce n'est pas ce que fait reserve(), mais ce que ne peut pas faire les autres fonctions par la suite.)
De toute façon, si un appel à reserve() change le fonctionnement du programme (à part bien sûr la vitesse d'exécution), tu as un bug quelque part.
Pas du tout. C'est une des b a ba des la durée de vie des itérateurs. La raison d'être même de réserve, c'est de permettre des push_back ou des insert par la suite sans invalider les itérateurs.
-- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Fabien LE LEZ wrote:
On Mon, 7 Feb 2005 23:16:49 +0100, "Alex" <rdpdo2002@yahoo.fr>:
MesString.reserve(1000);
- Il me semble que reserve() peut être une no-op (quelqu'un
peut confirmer ?)
Il est même garanti être un no-op si capacity() vaut plus que
son paramètre. Alors, dans une implémentation où le constructeur
initialise le vector avec max_size() capacité systèmatiquement.
(Mais évidemment, je parle des implémentations qu'on ne vera
jamais, parce qu'inutilisable.)
La norme garantit qu'après reserve, capacity() serait au moins
aussi grande que le paramètre de reserve(). Elle garantie aussi
que tant que la taille reste inférieur à cette capacité, les
pointeurs, les références et les itérateurs vers le vecteur
resteront valide. (En fait, ce qui importe, ce n'est pas ce que
fait reserve(), mais ce que ne peut pas faire les autres
fonctions par la suite.)
De toute façon, si un appel à reserve() change le
fonctionnement du programme (à part bien sûr la vitesse
d'exécution), tu as un bug quelque part.
Pas du tout. C'est une des b a ba des la durée de vie des
itérateurs. La raison d'être même de réserve, c'est de permettre
des push_back ou des insert par la suite sans invalider les
itérateurs.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
- Il me semble que reserve() peut être une no-op (quelqu'un peut confirmer ?)
Il est même garanti être un no-op si capacity() vaut plus que son paramètre. Alors, dans une implémentation où le constructeur initialise le vector avec max_size() capacité systèmatiquement. (Mais évidemment, je parle des implémentations qu'on ne vera jamais, parce qu'inutilisable.)
La norme garantit qu'après reserve, capacity() serait au moins aussi grande que le paramètre de reserve(). Elle garantie aussi que tant que la taille reste inférieur à cette capacité, les pointeurs, les références et les itérateurs vers le vecteur resteront valide. (En fait, ce qui importe, ce n'est pas ce que fait reserve(), mais ce que ne peut pas faire les autres fonctions par la suite.)
De toute façon, si un appel à reserve() change le fonctionnement du programme (à part bien sûr la vitesse d'exécution), tu as un bug quelque part.
Pas du tout. C'est une des b a ba des la durée de vie des itérateurs. La raison d'être même de réserve, c'est de permettre des push_back ou des insert par la suite sans invalider les itérateurs.
-- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
kanze
Alex wrote:
It is guaranteed that no reallocation takes place during insertions that happen after a call to reserve() until the time when an insertion would make the size of the vector greater than the size specified in the most recent call to reserve().
Une petite question en passant... Si pendant l'execution du prog on se rend compte que le reserve initial etait trop juste, y-a-til une maniere d'allouer plus d'espace en gardant la mémoire contigue ? (enfin, disons en "forcant" l'allocation a etre contigue; quitte a emmettre un message d'erreur, ou ajuster e programme si cela n'a pas été possible)
Un petit détail : la mémoire d'un std::vector est toujours contigu. Ça fait partie des exigeances de vector.
Mais je crois en fait que ce dont tu as besoin, c'est que les adresses des éléments restent valides. Et là, il n'y a rien. Si tu n'as pas fait un reserve() assez grand, il n'y a rien à faire.
Ceci dit, j'aimerais savoir un peu plus juste de quoi il s'agit. Parce qu'il doit y avoir un moyen de contourner le problème. Donc, par exemple, tu as parlé de renvoyer des void* chez des clients. Qu'est-ce qu'ils font avec ces void* ? Est-ce que renvoyer l'adresse du vector (plutôt que l'adresse de son contenu) ne ferait pas l'affair, par exemple ?
-- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Alex wrote:
It is guaranteed that no reallocation takes place during
insertions that happen after a call to reserve() until the
time when an insertion would make the size of the vector
greater than the size specified in the most recent call to
reserve().
Une petite question en passant... Si pendant l'execution du
prog on se rend compte que le reserve initial etait trop
juste, y-a-til une maniere d'allouer plus d'espace en gardant
la mémoire contigue ? (enfin, disons en "forcant" l'allocation
a etre contigue; quitte a emmettre un message d'erreur, ou
ajuster e programme si cela n'a pas été possible)
Un petit détail : la mémoire d'un std::vector est toujours
contigu. Ça fait partie des exigeances de vector.
Mais je crois en fait que ce dont tu as besoin, c'est que les
adresses des éléments restent valides. Et là, il n'y a rien. Si
tu n'as pas fait un reserve() assez grand, il n'y a rien à
faire.
Ceci dit, j'aimerais savoir un peu plus juste de quoi il s'agit.
Parce qu'il doit y avoir un moyen de contourner le problème.
Donc, par exemple, tu as parlé de renvoyer des void* chez des
clients. Qu'est-ce qu'ils font avec ces void* ? Est-ce que
renvoyer l'adresse du vector (plutôt que l'adresse de son
contenu) ne ferait pas l'affair, par exemple ?
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
It is guaranteed that no reallocation takes place during insertions that happen after a call to reserve() until the time when an insertion would make the size of the vector greater than the size specified in the most recent call to reserve().
Une petite question en passant... Si pendant l'execution du prog on se rend compte que le reserve initial etait trop juste, y-a-til une maniere d'allouer plus d'espace en gardant la mémoire contigue ? (enfin, disons en "forcant" l'allocation a etre contigue; quitte a emmettre un message d'erreur, ou ajuster e programme si cela n'a pas été possible)
Un petit détail : la mémoire d'un std::vector est toujours contigu. Ça fait partie des exigeances de vector.
Mais je crois en fait que ce dont tu as besoin, c'est que les adresses des éléments restent valides. Et là, il n'y a rien. Si tu n'as pas fait un reserve() assez grand, il n'y a rien à faire.
Ceci dit, j'aimerais savoir un peu plus juste de quoi il s'agit. Parce qu'il doit y avoir un moyen de contourner le problème. Donc, par exemple, tu as parlé de renvoyer des void* chez des clients. Qu'est-ce qu'ils font avec ces void* ? Est-ce que renvoyer l'adresse du vector (plutôt que l'adresse de son contenu) ne ferait pas l'affair, par exemple ?
-- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Alex
Ceci dit, j'aimerais savoir un peu plus juste de quoi il s'agit. Parce qu'il doit y avoir un moyen de contourner le problème. Donc, par exemple, tu as parlé de renvoyer des void* chez des clients. Qu'est-ce qu'ils font avec ces void* ? Est-ce que renvoyer l'adresse du vector (plutôt que l'adresse de son contenu) ne ferait pas l'affair, par exemple ?
Alors ca, c'est une très très bonne idée :) Merci ! (mais pourquoi n'y ai-je pas pensé plus tot !!)
Ceci dit, j'aimerais savoir un peu plus juste de quoi il s'agit.
Parce qu'il doit y avoir un moyen de contourner le problème.
Donc, par exemple, tu as parlé de renvoyer des void* chez des
clients. Qu'est-ce qu'ils font avec ces void* ? Est-ce que
renvoyer l'adresse du vector (plutôt que l'adresse de son
contenu) ne ferait pas l'affair, par exemple ?
Alors ca, c'est une très très bonne idée :) Merci ! (mais pourquoi n'y ai-je
pas pensé plus tot !!)
Ceci dit, j'aimerais savoir un peu plus juste de quoi il s'agit. Parce qu'il doit y avoir un moyen de contourner le problème. Donc, par exemple, tu as parlé de renvoyer des void* chez des clients. Qu'est-ce qu'ils font avec ces void* ? Est-ce que renvoyer l'adresse du vector (plutôt que l'adresse de son contenu) ne ferait pas l'affair, par exemple ?
Alors ca, c'est une très très bonne idée :) Merci ! (mais pourquoi n'y ai-je pas pensé plus tot !!)
Alex
Non, l'allocation supplémentaire n'a pas le droit d'être constante, il faut qu'elle soit multiple de la taille courante. Sinon, on a une complexitée amortie en O(n) pour l'insertion, au lieu de O(1).
En effet ça serait pas mal... je vais regarder dans les sources de stl si c'est le cas.
Les fuites sont peut-être dues à "un bug" dans STL. C'est que reserve 1000 fait marcher 1000 fois le constructeur de string, qui fait new.
Reserve n'appelle pas de constructeurs. Tu confonds avec resize.
Oui, j'ai vu dans les sources sous Windows et que reserve() agit par allocate() de la classe allocator qui alloue un espace contiguë en ayant la SIZE passée à reserve() multiplié par la sizeof de l'objet paramètre du template ! En effet, il n'y a pas de constructeur : ) Tout se passe ensuite par des iterateurs _First, _Last et _End
Non, l'allocation supplémentaire n'a pas le droit d'être constante, il
faut qu'elle soit multiple de la taille courante. Sinon, on a une
complexitée amortie en O(n) pour l'insertion, au lieu de O(1).
En effet ça serait pas mal... je vais regarder dans les sources de stl si
c'est le cas.
Les fuites sont peut-être dues à "un bug" dans STL. C'est que reserve
1000 fait marcher 1000 fois le constructeur de string, qui fait new.
Reserve n'appelle pas de constructeurs. Tu confonds avec resize.
Oui, j'ai vu dans les sources sous Windows et que reserve() agit par
allocate() de la classe allocator qui alloue un espace contiguë en ayant la
SIZE passée à reserve() multiplié par la sizeof de l'objet paramètre du
template ! En effet, il n'y a pas de constructeur : ) Tout se passe ensuite
par des iterateurs _First, _Last et _End
Non, l'allocation supplémentaire n'a pas le droit d'être constante, il faut qu'elle soit multiple de la taille courante. Sinon, on a une complexitée amortie en O(n) pour l'insertion, au lieu de O(1).
En effet ça serait pas mal... je vais regarder dans les sources de stl si c'est le cas.
Les fuites sont peut-être dues à "un bug" dans STL. C'est que reserve 1000 fait marcher 1000 fois le constructeur de string, qui fait new.
Reserve n'appelle pas de constructeurs. Tu confonds avec resize.
Oui, j'ai vu dans les sources sous Windows et que reserve() agit par allocate() de la classe allocator qui alloue un espace contiguë en ayant la SIZE passée à reserve() multiplié par la sizeof de l'objet paramètre du template ! En effet, il n'y a pas de constructeur : ) Tout se passe ensuite par des iterateurs _First, _Last et _End
Alex
Alex wrote:
Merci pour ta reponse, mais en fait je viens de m'appercevoir que c'est un autre vector dans mon prog qui etait mal désalloué... Je m'excuse pour le "spam", j'aurais du chercher un peu plus avant de poster ici (j'avais cru avoir cherché assez... mais non !)
Mais non, pas de quoi. Je soupçonnais une anomalie au niveau de STL mais c'est toujours bien se justifier qu'il y en a pas. En tout cas ici.
En fait ce que l'on attend d'une classe, surtout templatisée et container c'est que quelle que soit la méthode appelée de manière régulière, que la gestion de mémoire se fasse correctement. Et dans ton bout de code tout était dans la loi, alors il devait avoir une explication, et tu l'as trouvé !
Par exemple dans le cas de MFC (aie, aie, désolé pour le HS !!!!) leur classe CString admet un accès direct par GetBuffer() qui doit être suivie par ReleaseBuffer(). Mais entre les 2 on peut écrire où on veut et le résultat peut être inattendu.
Bien sur pour le string tu as troujour c_str(), et tu peux le passer à const_cast et faire n'importe quoi, mais c'est pas très régulier tout ça...
Alex wrote:
Merci pour ta reponse, mais en fait je viens de m'appercevoir que c'est un
autre vector dans mon prog qui etait mal désalloué... Je m'excuse pour le
"spam", j'aurais du chercher un peu plus avant de poster ici (j'avais cru
avoir cherché assez... mais non !)
Mais non, pas de quoi. Je soupçonnais une anomalie au niveau de STL mais
c'est toujours bien se justifier qu'il y en a pas. En tout cas ici.
En fait ce que l'on attend d'une classe, surtout templatisée et container
c'est que quelle que soit la méthode appelée de manière régulière, que la
gestion de mémoire se fasse correctement. Et dans ton bout de code tout
était dans la loi, alors il devait avoir une explication, et tu l'as trouvé
!
Par exemple dans le cas de MFC (aie, aie, désolé pour le HS !!!!) leur
classe CString admet un accès direct par GetBuffer() qui doit être suivie
par ReleaseBuffer(). Mais entre les 2 on peut écrire où on veut et le
résultat peut être inattendu.
Bien sur pour le string tu as troujour c_str(), et tu peux le passer à
const_cast et faire n'importe quoi, mais c'est pas très régulier tout ça...
Merci pour ta reponse, mais en fait je viens de m'appercevoir que c'est un autre vector dans mon prog qui etait mal désalloué... Je m'excuse pour le "spam", j'aurais du chercher un peu plus avant de poster ici (j'avais cru avoir cherché assez... mais non !)
Mais non, pas de quoi. Je soupçonnais une anomalie au niveau de STL mais c'est toujours bien se justifier qu'il y en a pas. En tout cas ici.
En fait ce que l'on attend d'une classe, surtout templatisée et container c'est que quelle que soit la méthode appelée de manière régulière, que la gestion de mémoire se fasse correctement. Et dans ton bout de code tout était dans la loi, alors il devait avoir une explication, et tu l'as trouvé !
Par exemple dans le cas de MFC (aie, aie, désolé pour le HS !!!!) leur classe CString admet un accès direct par GetBuffer() qui doit être suivie par ReleaseBuffer(). Mais entre les 2 on peut écrire où on veut et le résultat peut être inattendu.
Bien sur pour le string tu as troujour c_str(), et tu peux le passer à const_cast et faire n'importe quoi, mais c'est pas très régulier tout ça...