VCC capricieux, et borland.... [C++] - Programmation
Marsh Posté le 03-03-2002 à 14:32:23
Pour le destructeur, je dirais que tu doit faire un delete [] np; parceque tu alloues un tableau et pas un simple char. 
 
Pour l'opérateur d'affectation ( ainsi que le constructeur par recopie ), je dirais qu'il faut autant que possible passé le paramètre par reference sur un objet constant parceque le système peut utiliser ces opérateur quand tu passes un objet en paramètre à une fonction. Et puis de toute façon, c'est comme ça qu'il faut faire et pas autrement  
 
Marsh Posté le 03-03-2002 à 14:34:39
| slvn a écrit a écrit  : avec VCC, j ai un autre pb : quand je surcharge l operateur "=" par exemple, il plantage a l execution si le prototype de la fonction est: void HI::operator=(HI hi); mais pas si son prototype est : void HI::operator=(HI &hi); | 
 
Dans le cas 1 il va passer par le constructeur par copie (HI::HI(const HI&) ) pour instancier l'objet local hi mais pas dans le second cas. 
[jfdsdjhfuetppo]--Message édité par Verdoux--[/jfdsdjhfuetppo]
Marsh Posté le 03-03-2002 à 15:16:40
en effet c est bien la "reference" qui faisaient planter  
 
 
bon, c est corrigé, mais ca souleve un autre problème : operator= demande  un HI &hi en argument.. 
 
j avais redefinit l operateur + qui renvoyait un HI: 
 
HI HI::operator+(HI hi); 
 
et donc si j ai : 
 
HI hi1,hi2,hi3; 
hi1= (hi2+hi3);  ne marche pu car il faudrait que hi2+hi3 soit une reference  
 
 
c est d apres ce que me dit borland avant de compiler : 
[C++ Error] main.cpp(17): E2285 Could not find a match for 'HI::operator =(HI)' 
 
 VCC compile, mais me fait un plantage lors de l execution .. 
Marsh Posté le 03-03-2002 à 15:21:50
voici la fonction operator+ 
 
HI HI::operator+(HI &hi)  
{ 
 unsigned int i=0, ajout=0, retenu=0, k = 1 + (taille > hi.taille?taille:hi.taille); 
 
 HI resultat(k); //construit un objet, avec nb= new char[k] et taille=k; 
 
 for(i=0;i<k;i++) 
 { 
   ajout=retenu;   
        if(i<taille) 
          ajout += nb[i]; 
 
   if(i<hi.taille) 
 	ajout += hi.nb[i]; 
    
   resultat.nb[i] = ajout % 256 ; 
   retenu         = ajout / 256 ; 
 } 
 return resultat; 
} 
[jfdsdjhfuetppo]--Message édité par slvn--[/jfdsdjhfuetppo]
Marsh Posté le 03-03-2002 à 15:41:25
| slvn a écrit a écrit  : HI hi1,hi2,hi3; hi1= (hi2+hi3); ne marche pu car il faudrait que hi2+hi3 soit une reference   c est d apres ce que me dit borland avant de compiler : [C++ Error] main.cpp(17): E2285 Could not find a match for 'HI::operator =(HI)' | 
 
Ca doit pas correspondre à la ligne hi1 = hi2 + hi3 puisqu'il peut utiliser la référence du temporaire retourné par hi2.operator+(hi3) 
Marsh Posté le 03-03-2002 à 17:18:39
ce serait bien que dans ton exemple 
de code tu ne passes pas d'une notation 
a une autre (genre un HI qui se transforme 
en HugeInt) 
j'aurais du mal a croire que c'est juste du  
copier coller de ton code. 
 
une bonne idee de nous repasser l'integralite 
de ton code, copie-colle et sans les smileys :(. 
 
L'inconvenient des operateurs surcharges 
et qui est souligne dans la doc c'est que tu peux 
changer completement le sens des operateurs 
et donc rendre la comprehension du tout un peu delicate. 
Pour eviter les problemes il faut donc essayer 
le plus possible de s'en tenir a l'implantation 
par defaut. 
 
Quelques idees comme ca: 
HI &HI::operator =(const HI&); 
l'argument 1 est de type const pour eviter 
qu'il ne modifie accidentellement ton objet 
passe en argument. de plus il permet 
d'assigner depuis des objets de type const 
ce qui est primordial si ton argument n'est 
pas une lvalue !! (typiquement le resultat 
de a+b n'est pas une lvalue sauf si tu renvoies 
une reference explicitement). 
Le resultat est une reference vers l'objet *this 
(important). 
 
HI::HI(const HI&); 
C'est l'operateur de copie. La raison 
du const c'est pour la meme raison 
que ci dessus. Tu ne passes pas 
l'argument par valeur à l'operateur de Copie. 
Dans le cas contraire il serait oblige 
de s'appeler lui-meme !! 
Il renvoie implicitement une reference 
vers *this. 
 
HI HI::operator +(const HI&) const; 
Le premier const c'est pour la meme raison 
que ci-dessus. Le deuxieme const c'est pour la meme raison. 
(le premier argument est cache c'est *this !). 
Il ne renvoie pas une reference mais un objet temporaire 
const (important)! 
 
HI &HI::operator +=(const HI &); 
le const c'est pour la meme raison que les fois 
precedentes.  
L'operateur n'est pas const 
parce qu'il modifie l'objet courant 
(comme l'assignement). 
il ne peut donc pas operer sur des objets ou 
references const! 
(ex: (a+b)+=d; est illegal !) 
 
A+ 
LEGREG 
Marsh Posté le 03-03-2002 à 17:23:54
evidemment tu PEUX t'amuser 
a changer la semantique de tous 
les operateurs. 
Par exemple que l'operateur = renvoie un objet temp const 
ou que l'operateur + renvoie une reference vers *this. 
Mais gare aux prises de tete. 
parce que "naturellement" tu vas 
te fier au comportement "presume par defaut" 
des operateurs mais que tu as change 
pour des raisons X ou Y. 
 
A+ 
LEGREG 
Marsh Posté le 03-03-2002 à 17:36:45
Pendant qu'on y est  
 
 
Par reference(const) ou par valeur? 
je precise const parce que sinon y'a 
meme pas de question a se poser. 
Ben ca depend. 
Parfois c'est mieux de passer par reference; 
on s'epargne la copie de l'objet. 
mais parfois c'est mieux de passer par valeur; 
une fois l'objet copie on peut travailler 
dessus sans se soucier de savoir qu'il est 
const et sans faire de deferencement 
de pointeur (implicite)  
a chaque acces a une propriete de l'objet. 
 
A vous de voir 
 
A+ 
LEGREG 
Marsh Posté le 03-03-2002 à 17:46:06
 
 
en effet, ce n'est pas un copier-coller de mon code  , car je ne voulais pas decourager ceux qui voulaient m aider !
, car je ne voulais pas decourager ceux qui voulaient m aider ! 
 
mais, puisque cela semble necessaire, je vais le poster  
(je le poste tout de suite, enfin apres savoir comme "eviter" de creer des smileys a cause des  ": o" ) 
 
en fait, ce que je cherche a recreer, c est toutes les operations normales des "int"  (+ - * ^ %) mais avec des entiers de tailles quelconques  (que je code avec des char)
 (que je code avec des char) 
 
je cherche a faire en sorte qu il n y ait pas d instruction inutile (notement dnas les passages en parametre-reference-pointeur) 
 
et qu il n y ait pas de place de perdu  
(ex : a= b * c  : si b est sur 10 octects et c sur 20 octect, alors a est sur 30 octects) 
[jfdsdjhfuetppo]--Message édité par slvn--[/jfdsdjhfuetppo]
Marsh Posté le 03-03-2002 à 19:12:50
voici le bazaar : 
(qui fait planter le prog sous borland a cause du delete du constructeur......) 
 
(:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:o:
 
 
o:o:o:o:o:o) 
 
main.cpp: 
============================================== 
#include "HugeInt.hpp" 
#include "stdio.h" 
 
int main(int argc, char * argv) 
{ 
 
  HugeInt p("123456789" ); 
  HugeInt q("abcdefghijklmnopqrst" ); 
  HugeInt copie(q); 
  HugeInt somme; 
  HugeInt affectation; 
 
  printf("p         : " ); p.affiche_ascii(); 
  printf("de taille : %i octect %i bits\n\n", p.taille, 8 * p.taille); 
 
  printf("q         : " ); q.affiche_ascii(); 
  printf("de taille : %i octect %i bits\n\n", q.taille, 8 * q.taille); 
 
  somme = q + p; 
  affectation = q; 
 
 
  printf("somme     : " ); somme.affiche_ascii(); 
  printf("de taille : %i octect %i bits\n\n", somme.taille, 8 * somme.taille); 
 
  printf("copie q   : " ); copie.affiche_ascii(); 
  printf("de taille : %i octect %i bits\n\n", copie.taille, 8 * copie.taille); 
 
  printf("affect q  : " ); affectation.affiche_ascii(); 
  printf("de taille : %i octect %i bits\n\n", affectation.taille, 8 * affectation.taille); 
 
 
 
  //destruction 
  p.~HugeInt(); 
  q.~HugeInt(); 
  somme.~HugeInt(); 
  affectation.~HugeInt(); 
 
  getchar(); 
  return 0; 
} 
============================================== 
HugeInt.hpp 
============================================== 
//adresse basse = poids faible  
 
class HugeInt 
{ 
 public: 
 
   char * nb                      ; 
   unsigned int taille            ; 
 
   //constructeur-destructeur 
   HugeInt(void)                  ;//grand nombre nul 
   HugeInt(unsigned int taille )  ;//construit un grand nombre de 8*taille bits 
   HugeInt(char * grandNombre)    ;//construit un grand nombre de chaine donnée 
   HugeInt(const HugeInt& source) ;//constructeur de copie 
   ~HugeInt(void)                 ;//libere la memoire occupée 
 
   //methode 
   void affiche_chaine(void)      ; 
   void affiche_ascii(void)       ; 
    
   //operation 
   HugeInt operator+(HugeInt hi)  ; 
   HugeInt operator=(HugeInt hi)  ; 
}; 
============================================== 
HugeIn.cpp 
============================================== 
#include <iostream.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include "HugeInt.hpp" 
 
 
 
HugeInt::HugeInt(void) 
{ 
  nb = NULL; 
  taille = 0; 
  return; 
} 
 
HugeInt::HugeInt(unsigned int taille) 
{ 
  if( (HugeInt::nb=new char[taille]) == 0) 
  { 
    cout << "erreur allocation memoire" << endl; 
    exit(0); 
  } 
  HugeInt::taille = taille; 
  return; 
} 
 
 
 
HugeInt::HugeInt(char * grandNombre) 
{ 
  unsigned int i,k; 
  HugeInt::taille = k = strlen(grandNombre); 
 
  if((HugeInt::nb=new char[k]) == 0) 
  { 
    cout << "erreur allocation memoire" << endl; 
    exit(0); 
  } 
 
  for(i=0;i<k;i++) 
 HugeInt::nb[i]=grandNombre[k -1 -i]; 
  return; 
} 
 
 
 
HugeInt::HugeInt(const HugeInt& source) //constructeur de copie 
{ 
  unsigned int i; 
  taille=source.taille; 
  if((HugeInt::nb=new char[taille]) == 0) 
  { 
    cout << "erreur allocation memoire" << endl; 
    exit(0); 
  } 
  for(i=0;i<taille;i++) 
 nb[i]=source.nb[i]; 
  return; 
} 
 
 
//destructeur 
HugeInt::~HugeInt(void) 
{ 
 if (nb != NULL) 
 { 
  //delete nb;        //erreur ici  #################################### 
  nb=NULL; 
 } 
 taille=0  ; 
 return; 
} 
 
void HugeInt::affiche_chaine(void)  {........} 
void HugeInt::affiche_ascii(void)   {.......} 
 
 
 
 
HugeInt HugeInt::operator+(HugeInt hi) 
{ 
 unsigned int i=0, ajout=0, retenu=0, k = 1 + (taille > hi.taille? taille : hi.taille); 
 
 HugeInt resultat(k); 
 
 for(i=0;i<k;i++) 
 { 
   ajout=retenu;   
          if(i < taille) 
            ajout += nb[i]; 
 
   if(i < hi.taille) 
            ajout += hi.nb[i]; 
    
   resultat.nb[i] = ajout % 256 ; 
   retenu         = ajout / 256 ; 
 } 
 return resultat; 
} 
 
 
 
 
HugeInt HugeInt::operator=(HugeInt hi) 
{  
  taille  = hi.taille; 
  delete nb; 
   
  if( (nb = new char[taille]) == 0) 
  { 
    cout << "erreur allocation memoire" << endl; 
    exit(0); 
  } 
  memcpy(nb , hi.nb , taille); 
  return *this; 
} 
============================================== 
[jfdsdjhfuetppo]--Message édité par slvn--[/jfdsdjhfuetppo]
Marsh Posté le 03-03-2002 à 19:57:21
je debute en C++ et j essayais de tester les trucs par moi meme  
 
...je voulais savoir si on pouvais utiliser les destructeurs, en plein milieu du prog  je crois que oui.
 je crois que oui. 
 
d ailleurs, apres verification, le prog du dessus marche bien avec VCC mais plante(a la fin de l execution) avec Borland  
(quand le delete du constructeur est activé) 
Marsh Posté le 03-03-2002 à 19:59:29
Certes, mais c'est dans 99% des cas une mauvaise idée car le compilo l'appelle déjà pour toi. 
Et puis, comme signalé précédemment remplace delete nb par delete[] nb 
Marsh Posté le 03-03-2002 à 20:02:53
Et dans ton opérateur d'affectation, tiens compte du cas: 
a = a; 
[jfdsdjhfuetppo]--Message édité par Verdoux--[/jfdsdjhfuetppo]
Marsh Posté le 03-03-2002 à 20:06:08
si j ai besoin de reccuperer de la memoire en plein milieu du prog, faut bien que je fasse appelle au destructeur moi meme ?? 
 
le delete[] ne change rien....(j aurais meme tendance a dire que delete[] == delete, enfin d apres vu sur un bouquin, ils se servait aussi bien de l un comme de l autre pour reccuperer la memoire de leur tableau) 
 
sinon, bien vu pour le coup du a=a;  
 
Marsh Posté le 03-03-2002 à 23:59:18
| slvn a écrit a écrit  : si j ai besoin de reccuperer de la memoire en plein milieu du prog, faut bien que je fasse appelle au destructeur moi meme ?? | 
 
 
On n'a jamais de bonne raison d'appeler le destructeur explicitement. 
 
les cas qui se presentent: 
- ton objet est declare en global, il est alloue 
au demarrage et jamais libere jusqu'a la mort du programme. 
- ton objet est sur la pile (comme dans ton main) 
il est alloue a sa premiere apparition et 
desalloue comme toutes les autres variables locales 
a la sortie de la fonction. 
- ton objet est membre d'un objet. Il est alloue 
dans la memoire de ton objet (sur la pile ou sur le tas) 
sa duree de vie est strictement egale a celle de l'objet. 
-ton objet a ete alloue par new. Il est sur le tas 
et il n'est desalloue qu'apres un appel explicite a delete. 
 
Si tu veux liberer de la memoire en cours de process: 
si ton objet est sur la pile tu n'as pas d'autre solution 
que de le "recycler" parce que tu ne liberes pas a la main 
un objet alloue sur la pile. 
(ex: tu alloues un HugeInt, tu l'utilises dans une boucle 
dans une partie du scope avec une certaine valeur 
et dans l'autre partie du scope avec une autre valeur) 
Sinon si tu veux des noms differents tu alloues 
dynamiquement. 
Mais bon de l'allocation dynamique qui a le scope 
d'une fonction, ca s'appelle de l'allocation sur  
la pile.. (de toute facon, la plus grande 
partie de la memoire allouee par ton objet 
se retrouve sur le tas grace au new) 
 
| slvn a écrit a écrit  : le delete[] ne change rien....(j aurais meme tendance a dire que delete[] == delete, enfin d apres vu sur un bouquin, ils se servait aussi bien de l un comme de l autre pour reccuperer la memoire de leur tableau) | 
 
 
Un tableau initialise avec un new A[taille]; 
doit toujours etre desalloue avec delete[]. 
 
Pourquoi cette distinction? parce que C++ est mal 
fait et ne fait pas de difference 
entre le pointeur vers objet et le pointeur vers tableau. 
Ainsi quand tu vas faire le delete nb; 
il va appeler le destructeur pour le premier element 
et pas les suivants. 
 
Ok, tu vas dire qu'il n'y a pas de destructeur a appeler 
sur le type char et c'est probablement la raison 
pour laquelle ca va marcher mais si tu ne prends 
pas cette bonne habitude ca va rapidement 
etre le bordel dans ta gestion memoire 
quand tu alloueras des arrays de HugeInt ! 
 
surtout que des petits malins peuvent prevoir 
un mecanisme d'allocation et de construction 
different pour les objets seuls et les arrays 
et donc que appeler l'un pour l'autre 
aura des effets indetermines. 
 
A+ 
LEGREG 
Marsh Posté le 04-03-2002 à 00:12:15
| slvn a écrit a écrit  : je cherche a faire en sorte qu il n y ait pas d instruction inutile (notement dnas les passages en parametre-reference-pointeur) | 
 
 
Peine perdue: tu n'y arriveras pas en surchargeant les operateurs. 
La surcharge des operateurs c'est du sucre syntaxique, 
qui permet d'appliquer a des types non naturels des operateurs dans un esprit proche de celui des types naturels. 
Cela a un cout et ca s'appelle le cout d'abstraction. 
parfois le cout est non negligeable. 
 
Exemple: tu as trois matrices A, B et C 
de taille n*n. 
tu peux les additionner en une seule passe et sans objet intermediaire 
| Code : 
 | 
 
Sauf que pour flatter ton sens de l'ecriture 
de code elegante tu vas surcharger l'operateur 
addition de deux matrices. 
donc tu arriveras a l'ecriture tres succincte  
| Code : 
 | 
 
Mais cette ecriture necessite au moins 
deux matrices n*n intermediaires, 
peut-etre des copies et des deferencements inutiles. 
 
A+ 
LEGREG 
Marsh Posté le 04-03-2002 à 15:53:12
bon, donc faut pas que je me fasse d illusions quant aux performances de mes nouveaux operateurs alors  
  
 
pour les constructeurs, j avais entendu dire, qu on pouvait les utiliser en plein milieu du prog, par ex, ca facilitait le codage d une liste chainée   (lorsqu on detruit, on recolle la chaine au meme moment). 
mais de toute facon, ce qui prendra le plus de place, ce n est pas les objet, mais le tableau de char, pointé par "nb", donc au pire, je ferais une fonction, qui ne servira que pour faire un "delete [] nb". 
 
sinon, pile/tas, c est par rapport aux notions d asm ?? (la pile stock les variables locales, l adresse de la fonction, les parametres de la fonction,    et le tas stocke les constantes?) 
 
je viens, de resoudre les pb de "plantage" sous borland, en rajoutant les parametres " ......(const HugeInt&) const" 
..etant donné que j ai pas changé le code du prog je vois pas ce que ca a pu faire de plus, enfin, j ai peut etre une idée : 
si je fait :     
 
void fonction( HugeInt a); 
 
fonction(aaaaaa); 
 
le prog, fait une copie locale du parametre effectif aaaaaa. 
cette copie est utilisée au cours de la fonction, et est detruite a la fin -> d apres, le destructeur, il y a destruction et libereration de la zone memoire pointée par les pointeurs de la copie de aaaaaa.  et vu que les pointeurs de la copie ont meme valeur que les pointeurs de aaaaaa, alors le destructeurs va libere la memoire de aaaaaaa aussi ? 
 
donc en utilisant une reference, y a pas destructions, donc pas d erreur 
 
 
c pas facil d etre clair lol 
Marsh Posté le 03-03-2002 à 14:18:02
Borland, me fait une erreur lors a la fin de l execution de mon programme:
 
 
ca se produit a cause du destructeur que j appelle moi meme :
(et qui serait donc reappelé une seconde fois puisque le programme se termine)
HI::~HI(void)
{
if (nb != NULL) {delete nb ;nb=NULL;}
taille=0 ;
}
class HI
{
public:
char * nb ;
unsigned int taille ;
HugeInt::HugeInt(int a) ;
HugeIntt::~HugeInt(void) ;
}
HI::HI(int a)
{
nb = new char[a];
taille = a;
}
avec VCC, j ai un autre pb :
quand je surcharge l operateur "=" par exemple, il plantage a l execution si le prototype de la fonction est:
void HI::operator=(HI hi);
mais pas si son prototype est :
void HI::operator=(HI &hi);
... sachant, que je voudrais relalisé l operation :
HI hi1,hi2;
hi1=hi2;
etant donné que ca ne va pas modifier le parametre, pkoi veut il qu on le lui passe en tant que "reference"
le plus curieux, c est que sous borland y a le pb du destructeur, mais pas de l operateur, et que sous vcc c est exactement l inverse...
voila, je pense que ce sont pourtant des logiciels reputés ? donc c est surment moi qui ai du me planté, mais la j avoue que je capte pas....