Pointeurs changent de valeur 'seuls'

Résolu
wilvart Messages postés 47 Date d'inscription samedi 7 janvier 2006 Statut Membre Dernière intervention 13 décembre 2012 - 28 juin 2012 à 19:45
wilvart Messages postés 47 Date d'inscription samedi 7 janvier 2006 Statut Membre Dernière intervention 13 décembre 2012 - 29 juin 2012 à 14:12
Bonjour,

J'ai un très gros soucis de pointeur. Mon code sert à traiter une image. J'y ai trouvé plusieurs blocs representant des lignes ou bout de lignes (du texte) que je voudrais lier afin d'avoir la phrase entière.

Ma variable 'lines' me permet de stocker toutes mes lignes, une ligne étant composée de plusieurs blocs.

Dans le code ci dessous, j'ai simplifié les choses (je vais pas vous faire lire mes 10k de lignes..) en ciblant le problème.

Dans la trace, vous remarquerez que les adresses de mes lignes changent. C'est ce que je voudrais comprendre. Dans la suite de mon algo, j'utilise des pointeurs vers ces lignes, donc si l'adresse change, segfault et autres joyeuseries s'invite dans mon shell :D

(J'utilise la librairie opencv sous mac)

void ReceiptSection::createLines (std::vector<std::vector<cv::Rect*> >& lines, cv::Rect& currentLetter)
{
     lines.push_back( std::vector<cv::Rect*>());
     std::vector<cv::Rect*>& newLine = lines.back();
     newLine.push_back(&currentLetter);
     LOG("---------------- PTR lines.back : " << &(lines.back()), 3);
     cv::rectangle(_sectionImage, cv::Point(currentLetter.x, currentLetter.y), cv::Point(currentLetter.x+currentLetter.width, currentLetter.y + currentLetter.height), cv::Scalar(0), 2);
}




void ReceiptSection::main()
{
    std::vector<std::vector<cv::Rect*> > lines;

    // _extractedLetters est un attribut de ma classe correctement rempli
    // std::vector<cv::Rect> _extractedLetters;
    std::vector<cv::Rect>::iterator aLetterIt = _extractedLetters.begin();

    do
    {
LOG("---------------- Before createLines", 3);
displayLinesPtr(lines);

createLines(lines, *aLetterIt);

LOG("---------------- After createLines", 3);
displayLinesPtr(lines);

aLetterIt++;
   }
   while (aLetterIt != _extractedLetters.end());




void ReceiptSection::displayLinesPtr(const std::vector<std::vector<cv::Rect*> >& lines)
{
    LOG("----------------------------LinesPtr---------------------------", 3);

    int cpt=1;

    for(std::vector<std::vector<cv::Rect*> >::const_iterator lineIt=lines.begin(); lineIt!=lines.end(); ++lineIt, cpt++)
    {
    	LOG("ptrLines " << cpt << " = " << &(*lineIt), 3);
    }

    LOG("---------------------------------------------------------------", 3);
}





Enfin, voici la trace que j'obtiens lors du traitement d'une image contenant plusieurs blocs.
Comme je vous le disais, ce code est une version simplifié qui n'a pour but que de reproduire l'erreur à laquelle je suis confronté.



<receiptSection.cpp:370> ---------------- Before createLines
<receiptSection.cpp:942> ----------------------------LinesPtr---------------------------
<receiptSection.cpp:951> ---------------------------------------------------------------
<receiptSection.cpp:1145> ---------------- PTR lines.back : 0x10115aa50

<receiptSection.cpp:373> ---------------- After createLines
<receiptSection.cpp:942> ----------------------------LinesPtr---------------------------
<receiptSection.cpp:948> ptrLines 1 = 0x10115aa50
<receiptSection.cpp:951> ---------------------------------------------------------------

<receiptSection.cpp:370> ---------------- Before createLines
<receiptSection.cpp:942> ----------------------------LinesPtr---------------------------
<receiptSection.cpp:948> ptrLines 1 = 0x10115aa50
<receiptSection.cpp:951> ---------------------------------------------------------------
<receiptSection.cpp:1145> ---------------- PTR lines.back : 0x10115a838

<receiptSection.cpp:373> ---------------- After createLines
<receiptSection.cpp:942> ----------------------------LinesPtr---------------------------
<receiptSection.cpp:948> ptrLines 1 = 0x10115a820
<receiptSection.cpp:948> ptrLines 2 = 0x10115a838
<receiptSection.cpp:951> ---------------------------------------------------------------



Merci d'avance !

5 réponses

cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
28 juin 2012 à 23:57
Bonjour.

Tout d'abord, je te déconseille l'usage d'un std::vector de std::vector. C'est généralement pas terrible. Un boost::multi_array est plus adapté. On peut aussi créer un std::vector à une seule dimension de taille N*N et feinter à l'usage en appelant "[x * size + y]" au lieu de "[x][y]".
Néanmoins, si tu ne veux pas de dépendance à boost ou ne pas réécrire ton code (ce qui est compréhensible), dans ce cas, fais au moins attention à une chose:
Un std::vector n'a pas ses éléments fixe en mémoire !

En effet, il y a une optimisation qui consiste à doubler la taille de la capacité si la taille venait à dépasser cette capacité.
Ex:
Si tu insère un 2+ éléments, la taille est de 2+, mais la capacité est de 4.
Si tu insère un 4+ éléments, la taille est de 4+, mais la capacité est de 8.
Si tu insère un 8+ éléments, la taille est de 8+, mais la capacité est de 16.
etc...

Ça évite de refaire une allocation à chaque ajout d'élément. Le souci, c'est que ça te fais croire, à tord que la zone mémoire est toujours la même (surtout quand tu as beaucoup d'éléments, vu que tu ne réalloues pas souvent).
Il faut savoir que si en augmentant la capacité, il n'y a pas assez de place en mémoire pour avoir tes éléments de manière contigües, alors realloc est utilisé (ce qui change la zone mémoire).

En d'autre terme, tu ne peux absolument pas prendre l'adresse d'un élément dans un std::vector !
On ne fait jamais de "std::vector<T>" en prenant l'adresse de T, celle-ci pouvant changer en cas d'ajout ou de suppression d'élément dans le tableau.
Pour résoudre ton problème, tu peux tout à fait faire un std::vector<std::vector<cv::Rect*>*>. Si le pointeur change de place, ce n'est pas grave, car il pointera toujours sur la zone que tu veux.

(J'utilise la librairie opencv sous mac)

Bibliothèque, merci :)

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
3
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
29 juin 2012 à 11:39
Du coup la solution la moins couteuse en temps (pour ce projet) est belle et bien de faire un std::vector<std::vector<cv::Rect*>*> et par conséquent de gérer la mémoire de façon un peu plus hard.

J'ai oublié de préciser que tu auras de bien meilleures performances en utilisant un pointeur sur "std::vector", vu qu'en cas de réallocation, tu ne copieras que le pointeur et non tous les (gros) sous tableaux. De plus, les pointeurs étant bien moins gros que les vecteurs, tu auras beaucoup moins de chance d'avoir un déplacement mémoire en cas de realloc.
Il est possible que tu constates une amélioration à ce niveau là.

Je ne connais pas la différence, pour moi tout est une lib/framework/biblio/... :D

- Une bibliothèque est un fichier compilé contenant des fonctions prêtes à être utilisé par un autre exécutable.
- Une librairie est un magasin où on achète des livres (rien à voir avec du code, mais les gens traduisent "library" incorrectement... C'est un "faux-ami" anglais.)
- Un framework n'est pas forcément un code compilé, ça peut être une suite d'outils, de fonction et/ou de bibliothèque qui te facilitent la vie, mais t'oblige à suivre une direction bien précise. Par exemple Qt est un framework qui te permet de développer des
applications graphiques, mais tu auras alors besoin de toutes la suite d'outils fournis avec pour que ça fonctionne (qmake, par exemple).

Merci beaucoup de ton aide !

Je t'en prie. N'hésite pas si tu as d'autre question.

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
3
wilvart Messages postés 47 Date d'inscription samedi 7 janvier 2006 Statut Membre Dernière intervention 13 décembre 2012
29 juin 2012 à 11:13
Merci beaucoup de ton aide !

Effectivement, je n'aurais pas du utiliser de std::vector... Je suis prévenu pour la prochaine fois !

Du coup la solution la moins couteuse en temps (pour ce projet) est belle et bien de faire un std::vector<std::vector<cv::Rect*>*> et par conséquent de gérer la mémoire de façon un peu plus hard.

[quote](J'utilise la librairie opencv sous mac)

Bibliothèque, merci :) /quote

Je ne connais pas la différence, pour moi tout est une lib/framework/biblio/... :D


Encore merci !!!
0
yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
29 juin 2012 à 13:08
Salut,

Des réponses aussi claires, ça fait réver !

Bye...
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
wilvart Messages postés 47 Date d'inscription samedi 7 janvier 2006 Statut Membre Dernière intervention 13 décembre 2012
29 juin 2012 à 14:12
:D
0
Rejoignez-nous