[Solved] Erreur d'acces memoire a l'execution

Erreur d'acces memoire a l'execution [Solved] - C++ - Programmation

Marsh Posté le 12-04-2006 à 17:13:40    

J'ai une petite question concernant les mysteres de la gestion memoire en C++.
Voici les classes A, B et BImpl:
 

Code :
  1. class B
  2. {
  3. public:
  4.    virtual void printHello() = 0;
  5. };
  6. class BImpl : public B
  7. {
  8. public:
  9.    void printHello()
  10.    {
  11.       printf("Hello",%s);
  12.    }
  13. };
  14. class A
  15. {
  16. public:
  17.    ~A()
  18.    {
  19.       delete(_myBImpl);
  20.       _myBImpl = NULL;
  21.    }
  22.    void setAttribute(B* myB)
  23.    {
  24.       _myBImpl = static_cast<BImpl*>(myB);
  25.    }
  26.    B &getAttribute()
  27.    {
  28.       return *_myBImpl;
  29.    }
  30. private:
  31.    BImpl* _myBImpl;
  32. };


 
Et ma fonction de test:
 

Code :
  1. int main()
  2. {
  3.    BImpl b;
  4.    A a;
  5.    b.printHello();
  6.    a.setAttribute(&b);
  7. }


 
Ce test plante a l'execution. Apparemment un pb d'acces memoire.
 
Si par contre j'utilise la factory suivante:
 

Code :
  1. class FactoryB
  2. {
  3.    public:
  4. FactoryB() {}
  5. ~FactoryB() {}
  6. static B* createBInstance()
  7.         {
  8.  BImpl *bPtr = 0;
  9.  bPtr = new(BImpl);
  10.  return bPtr;
  11.         }
  12. };


 
Et les test suivant:
 

Code :
  1. int main()
  2. {
  3.    BImpl *b = static_cast<BImpl*>(FactoryB::createBInstance());
  4.    A a;
  5.    b->printHello();
  6.    a.setAttribute(b);
  7. }


 
Ca marche nickel! Quelqu'un pourrait-il me dire en detail ce qui se passe dans le premier cas? Pourquoi ca plante?
 
Merci d'avance


Message édité par agyspace le 13-04-2006 à 19:10:08
Reply

Marsh Posté le 12-04-2006 à 17:13:40   

Reply

Marsh Posté le 12-04-2006 à 17:53:00    

Petit indice que j'ai oublie! Le crash se fait quand on sort de la fonction, en particulier lors de la destruction de l'objet A, c'est l'instruction "delete(_myBImpl)" qui ne passe pas.
 
L'erreur se manifeste sous la forme d'une fenetre popup Visual Studio.
 
Et enfin pour ceux qui se demandent pourquoi je fais un cast dans la methode setSecurity() de A, c'est parce en vrai, je n'utilise pas des classes A, B et BImpl mais d'autres classes plus etoffees et que j'ai besoin de faire ce cast a ce moment la.

Reply

Marsh Posté le 12-04-2006 à 17:54:42    

Et je me suis trompee aussi sur l'instruction de delete. Il faut lire bien evidemment:
delete _myBImpl;
et non pas
delete(myBImpl);

Reply

Marsh Posté le 12-04-2006 à 19:06:42    

dans ton premier exemple, t'as un delete, mais pas de new, y a pas à chercher ...
 
 
sinon vire ces cast, ils ne servent à rien.
 
 
bPtr = new(BImpl); -> new BImpl;

Reply

Marsh Posté le 12-04-2006 à 19:10:24    

ligne 12: %s?
ligne 27: fille=base? d'habitude c'est le contraire
 
dans le main:
ligne 3: ``b`` est mis sur la pile
ligne 6: ``a`` va supprimer ``b`` avec un delete (qui supprime sur le tas)
Si tu utilise delete avec un objet créé sur la pile tu obtient une violation mémoire.

Reply

Marsh Posté le 13-04-2006 à 09:57:00    

Bon, quelques mises au point s'imposent je crois :P:
Comme je l'ai dit les petits bouts de code que j'ai donne sont une simplification de mon vrai code.
Je me suis trompee sur la syntaxe du printf (que j'ai mis juste pour l'exemple mais en realite je ne fais pas de printf je fais un autre buisiness :))

Code :
  1. printfHello()
  2. {
  3.    printf("%s \n","Hello" );
  4. }


 
Ensuite, le cast dans l'exemple que j'ai donne est inutile c'est vrai. Dans mon vrai code j'utilise dans la classe A des methodes de BImpl non definis dans B, ce qui me force a faire un cast de B vers BImpl.
 
Pour repartir sur le fon du probleme:
Si je comprends bien un objet qui n'est pas cree avec new est cree sur la pile, et faire un delete dessus cree une violation memoire. C'est bien ca?

Reply

Marsh Posté le 13-04-2006 à 10:28:34    

> C'est bien ca?  
- tout à fait
 
> Dans mon vrai code j'utilise dans la classe A des methodes de BImpl non definis dans B, ce qui me force a faire un cast de B vers BImpl.
- ton vrai code est faux :D setAttribute() devrait prendre dans ce cas un BImpl* en paramètre.

Reply

Marsh Posté le 13-04-2006 à 10:40:46    

Et bien en fait, c'est un peu complique, mais je suis obligee d'utiliser le type B* en interface. Mon client ne doit pas connaitre (pour diverses raisons internes a ma societe) la classe BImpl. D'ou le cast...

Reply

Marsh Posté le 13-04-2006 à 13:00:11    

Utilise le rtti() et un throw().

Reply

Marsh Posté le 13-04-2006 à 16:35:03    

le rtti()? je ne connais pas :(

Reply

Marsh Posté le 13-04-2006 à 16:35:03   

Reply

Marsh Posté le 13-04-2006 à 16:42:12    

J'ai pas de doc particulière à te proposer, mais il y en a plein sur le net.
Chaque classe possède un numéro, qui identifie son type. Pour vérifier que le type d'une classe polymorphe est bien celui que tu attends, tu vérifie son rtti. Sinon, tu lance une exception. Comme ça le programmeur qui utilise ta librairie et qui mets en paramètre une classe incompatible est prévenu par un message d'erreur.
C'est néanmoins une méthode à n'utiliser qu'en dernier recours. Vérifie d'abord que tu ne peut pas réarranger plus judicieusement ton diagramme objet.

Reply

Marsh Posté le 13-04-2006 à 19:09:52    

Ok merci pour ton aide :)

Reply

Sujets relatifs:

Leave a Replay

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