Compilation bizarre avec VS.NET...

Compilation bizarre avec VS.NET... - C++ - Programmation

Marsh Posté le 04-10-2002 à 23:52:09    

voilà j'ai un système de template du style:
 

Code :
  1. template <class T> class rvector
  2. {
  3.    T *Data;
  4.    int Size;
  5.    int Capacity;
  6. ....
  7. ....
  8.     int Alloc(int q=1);
  9.     inline operator T* () const
  10.     {
  11. return Data;
  12.     } 
  13. }


 
c'est une template qui maintiens une collection d'objet (style vector<> de la STL, mais en mieux selon mes critères de performances, les allocations mémoire crêtes sont limitées par un realloc()+placement new)
 
Alloc() alloue un objet en plus dans la collection (DATA peut bouger), et retourne l'indice dans le tableau du nouvel objet.
 
operator T* me retourne Data, pour utiliser [] & co....
 
--------------------------
 
j'ai un comportement que je trouve anormal avec visual studio .NET:
 
j'ai un rvector<Strip> Strips;
 
et à un moment je fais:
 

Code :
  1. Strip &CStrip = Strips[ Strips.Alloc() ];


 
Je compile en DEBUG, pas d'optimisations.
 
Donc on a CSTrip qui maintiens un nouvel objet par adresse.
Strips.Alloc() crée le nouvel objet.
 
Dans ce cas Data à l'intérieur de la template (dumoins Strips), est bougé par Alloc().
 
Hors le compilateur semble générer du code tel que l'ancien Data est utilisé pour Strips[ ], et non le nouveau modifié par Alloc().
 
En gros, quand le compilo bouffe le Strips[ Strips.Alloc() ], il:
 
1) Prends le Data via l'opérateur T*
2) Effectue Alloc() et retourne l'indice du nouvel objet
3) Alloc modifie Data de Strips
4) l'objet pointé par CStrip est ANCIEN DATA[ indice d'alloc() ]
 
Ce qui fait que évidemment, ça chie.
 
si je contourne le comportement du compilateur, par un:
 
int ind=Strips.Alloc();
Strip &CStrip=Strips[ind];
 
ça marche....
 
alors est-ce normal que le compilo utilise d'abord l'operator T*() avant Alloc() :??:  
 
ou alors est-ce dû au fait qu'il y a des truc bizarres dû au fait que ce soit une template à la base  :??:  
 
je peux contourner le problème, mais j'aimerais comprendre....

Reply

Marsh Posté le 04-10-2002 à 23:52:09   

Reply

Marsh Posté le 05-10-2002 à 00:08:17    


sans le "const" et l'inline de la déclaration operator T* ()
 

Code :
  1. inline operator T* () const
  2.         {
  3.        return Data;
  4.         }


 
le compilo fait la même chose....

Reply

Marsh Posté le 05-10-2002 à 00:21:28    

et les formes:
 

Code :
  1. Strip &CStrip = *( Strips + Strips.Alloc() );
  2. Strip &CStrip = *( Strips.Alloc() + Strips );


 
chient autant (ça aurait pu être une subtilité operator T* () / operator [] (int i) )
 
par contre idem les formes MARCHENT:
 

Code :
  1. int yo=Strips.Alloc();
  2. Strip &CStrip = *( Strips + yo );
  3. Strip &CStrip = *( yo + Strips );


 
toujours en DEBUG... (compilation boeuf)
 
 
 
 
 
 
 
en fait ce con utilise l'operator T*() trop tôt.....
 
debug ASM pour Strip &CStrip = Strips[ Strips.Alloc() ];
 

Code :
  1. ; 516  :  Strip &CStrip = Strips[ Strips.Alloc() ];
  2. mov ecx, DWORD PTR _this$[ebp]
  3. add ecx, 92     ; 0000005cH
  4. call ??B?$rvector@VStrip@@@@QBEPAVStrip@@XZ ; rvector<Strip>::operator Strip *
  5. mov esi, eax
  6. push 1
  7. mov ecx, DWORD PTR _this$[ebp]
  8. add ecx, 92     ; 0000005cH
  9. call ?Alloc@?$rvector@VStrip@@@@QAEII@Z ; rvector<Strip>::Alloc
  10. shl eax, 5
  11. add esi, eax
  12. mov DWORD PTR _CStrip$[ebp], esi


 
et idem pour la forme Strip &CStrip = *(Strips.Alloc() + Strips);
 

Code :
  1. ; 516  :  Strip &CStrip = *(Strips.Alloc() + Strips);
  2. mov ecx, DWORD PTR _this$[ebp]
  3. add ecx, 92     ; 0000005cH
  4. call ??B?$rvector@VStrip@@@@QBEPAVStrip@@XZ ; rvector<Strip>::operator Strip *
  5. mov esi, eax
  6. push 1
  7. mov ecx, DWORD PTR _this$[ebp]
  8. add ecx, 92     ; 0000005cH
  9. call ?Alloc@?$rvector@VStrip@@@@QAEII@Z ; rvector<Strip>::Alloc
  10. shl eax, 5
  11. add esi, eax
  12. mov DWORD PTR _CStrip$[ebp], esi


Message édité par bjone le 05-10-2002 à 00:40:15
Reply

Marsh Posté le 05-10-2002 à 00:57:00    

Bon bin autant pour moi, ça doit être défini dans la norme ANSI, Borland C++ Builder 6 fait la même chose  [:spamafote]  

Reply

Marsh Posté le 05-10-2002 à 01:42:58    

Ajoute dans ta classe rvector

Code :
  1. T operator[](int i){return Data[i];}


 
Autrement le compilo transforme
Strips[ Strips.Alloc() ]  
en, comme tu l'as écrit,:
*(Strips + Strips.Alloc())
(et dans ce cas, le comportement est celui attendu)


Message édité par verdoux le 05-10-2002 à 01:53:08
Reply

Marsh Posté le 05-10-2002 à 04:14:26    

Les compilateurs sont libres d'évaluer les opérandes d'une expresion dans l'ordre qu'ils veulent (standard C/C++).
Exceptions: || && ?: (contrôle de flux)
 
Donc, ces codes ont des comportements dépendants du compilateur:

Code :
  1. Strips[ Strips.Alloc() ];
  2. i= i++;


 
Je pense que rvector::Alloc devrait renvoyer un pointeur (ou référence) sur l'élément alloué.

Code :
  1. *Strips.Alloc(...); //le nouvel l'élément
  2. Strips.Alloc(...) - &Strips[0]; //l'indice du nouvel élément
  3. Strips.Size //aussi l'indice


 
Mais es-tu sûr de faire mieux qu'un conteneur STL ?

Code :
  1. vector::bush_back(obj) //ajouter un élément à la fin
  2. vector::reserve(n); //fixer le pas de réallocation
  3. vector::resize(n); //redimensionner
  4. vector::size(); //dimension


---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le 05-10-2002 à 11:08:36    

oui le vector passe par new/delete...
 
en fait si tu as un tableau de 256 mo de capcité alloué, et quand tu arrives au bout de la capacité, il:
 
1) crée un tableau de la nouvelle taille (pour 256 mo d'objets + le delta qu'il se donne)
2) recopie l'ancien tableau dans le nouveau
3) supprimme l'ancien.
 
ce qui fait que l'occupation mémoire crête au moment de l'agrandissement est 2x la taille utile...
et le cpu se bouffe la recopie....
 
y'a les listes & co..., mais dans certains cas je prèfère une collection en tableau, qu'en liste chaine ou autre, c'est plus efficace au niveau cache cpu....
 
histoire de compenser ça, la seule technique qu'ils ont trouvés, c'est foutre un gros delta....


Message édité par bjone le 05-10-2002 à 11:12:59
Reply

Marsh Posté le 05-10-2002 à 11:10:01    

verdoux a écrit a écrit :

Ajoute dans ta classe rvector

Code :
  1. T operator[](int i){return Data[i];}


 
Autrement le compilo transforme
Strips[ Strips.Alloc() ]  
en, comme tu l'as écrit,:
*(Strips + Strips.Alloc())
(et dans ce cas, le comportement est celui attendu)




 
oui mais si j'ai les deux l'operator T* (), l'operator T operator [](int i), le compilo gueule passque y'a deux possibilitées ambigues....

Reply

Marsh Posté le 05-10-2002 à 11:12:09    

enfin c po grave, comme ça se comporte pareil avec le C++ builder 6, je vais passer par un int temporaire....
 
pour Alloc(), je préfère garder l'indice que l'adresse effective qui peut bouger....

Reply

Marsh Posté le 06-10-2002 à 02:06:20    

Citation :

histoire de compenser ça, la seule technique qu'ils ont trouvés, c'est foutre un gros delta....

Ben oui... y'a malheureusement pas 36 façons de redimensionner un conteneur contigü...
La STL peut être implémentée avec utilisation de realloc, pour autant que je sache.
 
Au niveau le plus simple, on joue au devin avec vector::reserve().
Au niveau complexe, on s'intéresse au paramètre allocator des patrons conteneurs (c'est pas de la tarte).


---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le 06-10-2002 à 02:06:20   

Reply

Marsh Posté le 06-10-2002 à 10:36:47    

vi tout à fait, je me doutais que y'avais moyen d'y arriver par les allocators, mais quand je vois comment les Docs C++ sont foutues, j'ai fait au revoir...
 
sinon y'a une raison simple pour laquelle ils ont pas utilisés le realloc(), et que j'ai tout de suite pris en considération, comme le realloc peut bouger l'adresse de base du tableau, si l'objet A mis en vector va mettre sa propre adresse dans un autre objet B (via les constructeurs et le destructeur), et que l'addresse de l'objet A bouge à cause d'un realloc(), le pointeur de B est foiré...
 
donc dans la pure logique c++, un vector qui utilise realloc() peut être dangereux si y'a des pointeurs croisés de partout....
 
mais un fois que tu le sais, tu fais attention à ce que tu mets dans un vector<> qui utilise realloc().

Reply

Marsh Posté le 06-10-2002 à 10:40:43    

Musaran a écrit a écrit :

Citation :

histoire de compenser ça, la seule technique qu'ils ont trouvés, c'est foutre un gros delta....

Ben oui... y'a malheureusement pas 36 façons de redimensionner un conteneur contigü...
La STL peut être implémentée avec utilisation de realloc, pour autant que je sache.
 
Au niveau le plus simple, on joue au devin avec vector::reserve().
Au niveau complexe, on s'intéresse au paramètre allocator des patrons conteneurs (c'est pas de la tarte).




 
par contre y'a un truc que j'ai pas analysé, c'est comment vector<> se comportait lorsque l'on mets une grande quatitée d'objet et qu'on les libère....
 
passke dans mon rvector<>, je realloc pour libérer de la mémoire à l'os quand la capacité-size > 2*delta lors des supressions.
 
sinon c'est génial le placement new....

Reply

Marsh Posté le 07-10-2002 à 02:59:28    

Le standard du C++ spécifie bien que l'agrandissement d'un conteneur comme vector peut rendre tous les itérateurs/pointeurs invalides.
Pour cette raison, les conteneurs contigüs ne libèrent pas la mémoire qu'ils s'octroient. Le seul moyen, c'est de le supprimer.
Ils n'ont pas trouvé de solution simple et efficace à cela. C'est mon plus grand reproche à vector: forcément dynamique.
 
J'ai un trou pour le placement new.
Il n'a pas de delete (individuel) correspondant, et on est responsable de l'appel des destructeurs, c'est bien ça ?


---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le 07-10-2002 à 09:33:15    

oui, que je realloc(), je fais un placement new() sur les objets alloués, et je fais un ~T() explicite pour les destructions...

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed