# [C++] STL + pointeurs = Segmentation Fault ! (résolu)

## Magic Banana

Je sais que ce genre de sujet n'a rien de Gentooesque mais n'étant "introduit" dans aucune communauté C++, je me permets de tenter ma chance parmi les codeurs qui errent par ici.

Voilà une version simplifiée de mon problème :

```
#include <vector>

class A

{

 public:

  A();

  std::vector<A*> v;

};
```

```
#include "A.h"

#include "B.h"

A::A()

{

  v.push_back(new B());

}
```

```
class B : public A

{

};
```

```
#include "A.h"

class C

{

 public:

  C();

  C(const C& c);

  std::vector<A*> w;

};
```

```
#include "C.h"

C::C()

{

  w.push_back(new A());

}

C::C(const C& c)

{

  w.push_back(new A(*(c.w.front()))); // ou w.push_back(c.w.front()) ou ...

}
```

```
#include "C.h"

int main(unsigned int argc, char* argv[])

{

  C c1;

  C c2(c1);

}
```

Les objets de type A peuvent être spécialisés en B. Ils contiennent un vecteur de pointeurs sur des objets de type A (le polymorphisme obligeant les pointeurs). Un objet de la classe C a, lui aussi, un attribut qui est un vecteur de pointeurs sur des objets de type A (toujours à cause du polymorphisme). Lorsque je souhaite copier (en partie) ce vecteur pour créer un nouvel élément de type C, il ne semble y avoir aucune méthode mettant à l'abri d'une erreur de Segmentation (qui n'est signalée qu'à la fin de l'exécution). Je ne cherche pas à copier le pointeur mais bien à obtenir un nouveau pointeur vers une copie de l'objet pointé.

```
$ g++ *.cpp && ./a.out 

Erreur de segmentation (core dumped)
```

J'ai passé la journée sur le Web a cherché une solution en vain.  :Crying or Very sad:   Quelqu'un relèvera-t-il le défi ici ?

EDIT : En fait, ceci n'est pas vraiment mon problème puisque l'erreur de segmentation a lieu même sans le push_back (mais avec ce qui est à l'intérieur). Quoi qu'il en soit, j'aimerais grandement savoir comment vous concevriez ce genre de structures. J'ai la nette impression que je m'y prends mal...  :Crying or Very sad: Last edited by Magic Banana on Wed Apr 11, 2007 2:59 pm; edited 1 time in total

----------

## sno35

Bonsoir,

Ton constructeur de A est, hum, rigolo :

il instancie un descendant de A qui va donc se construire en appelant le constructeur de A ...

dépassement de pile en vue, à mon avis.

Mes2cts.

----------

## _Seth_

Je raconte sans doute une connerie mais as tu fait un makefile ? Ta compilation en une ligne me semble un peu suspecte.

----------

## kwenspc

Non la ligne de compilation me semble bonne. Je rejoins sno35, tel qu'est fait le code c'est foireux. 

D'ailleurs c'est assez crade que dans une classe mère on appelle le constructeur d'une classe fille.

----------

## xaviermiller

http://mindview.net/Books/books.html#ThinkingInCPlusPlus

----------

## Magic Banana

Effectivement, mon constructeur de A est "rigolo". Je vous explique : je veux une classe dont les instances sont des espaces de dimension n quelconque. L'idée est donc que le traitement à un niveau n est propagé au niveau n-1 et ce jusqu'à une dimension 1. La classe B est donc le modèle d'objet de dimension 1 (où les traitements sont effectuées). Autrement dit un objet de type A contient un vecteur d'objet de type A mais de dimension plus petite (1 de moins) et ainsi de suite jusqu'à obtenir des objets de type B (pour lesquel les vecteurs sont vides).

Vous auriez choisi un autre schéma de conception ?

La compilation se passe bien. Le problème n'est pas là.

Je connaît bien les livres de Bruce Eckel mais mon problème ne rentre pas dans le cadre des cas d'école... à moins qu'il s'agisse d'une problème simple à l'aspect inutilement complexe. Je suis en effet en train de considérer la possibilité d'un problème lié au fait que la copie d'objets de la classe A (lors de l'affectation au vecteur w) est mal faite (copie des pointeurs de v et non duplication des objets pointés). Bref, le bête problème de copie profonde d'une collection de pointeurs. Je regarde cela de plus près tout de suite et vous tiens au courant.

Merci d'avance pour votre aide.

----------

## xaviermiller

en gros, tu veux appliquer des patterns du genre "fabrication" ou "fabrique abstraite" ?

----------

## xaviermiller

sinon, j'ai trouvé ce qui ne va pas : ta classe A crée un B lors de son initialisation. B, héritant de A, construit un A à sa construction. Et hop, récursivité...

----------

## kwenspc

 *XavierMiller wrote:*   

> sinon, j'ai trouvé ce qui ne va pas : ta classe A crée un B lors de son initialisation. B, héritant de A, construit un A à sa construction. Et hop, récursivité...

 

c'est ce que sno35 a noté aussi  :Wink: 

----------

## Magic Banana

Vous avez raison... mais en fait non !  :Laughing:  L'exemple simple que j'ai voulu construire à partir de mon problème réel (quelques milliers de lignes), n'est pas juste... Il faut en fait ajouter l'idée d'un nombre de dimension (argument du constructeur qui n'est donc plus un constructeur par défaut) qui est testé et qui, dans le cas où la dimension tombe à un appel le constructeur de B, sinon rappel le constructeur de A après avoir décrémenté cet argument.

Je regarde si le problème semble provenir de l'absence de constructeur de copie dans A (qui serait appelé lors du push_back sur w). Si ce n'est pas le cas, j'essaie de vous refaire mon exemple minimalliste mais qui correspondrait vraiment à mon problème.

Désolé...

----------

## xaviermiller

là, je ne comprends pas : si B hérite de A, à sa construction, il doit construire un A avant lui. Et si A construit un B, on a un problème...

Je pense qu'il y a un problème d'abord de conception : essaie d'avoir du recul, de voir le rôle de chaque objet avant de foncer dans une implémentation alambiquée. Et tout ne peut pas être fait par un constructeur, il faudra peut-être d'abord construire tes A et B, puis les initialiser.

Tu veux faire quoi au juste ? des conteneurs ?

----------

## Magic Banana

J'ai beaucoup réfléchi à la conception. Simplement, en voulant simplifier mon problème, je ne traduis pas le problème de départ et m'en excuse. Le constructeur de A est, en fait, quelque chose du genre :

```
A::A(int n)

{

  if (n == 1)

    {

       v.push_back(new B());

    }

  else

    {

      v.push_back(new A(n-1));

    }

}
```

En revanche le constructeur par défaut de A est vide (donc pas de problème de récursivité). Vous voyez ce que je veux dire ?

----------

## xaviermiller

ah, ok  :Wink: 

ton v, est-il bien construit avant de l'appeler ?

que donne le debug dans le constructeur de A ?

----------

## Magic Banana

Je n'ai pas fait de debug car jusqu'à maintenant (et l'arrivée d'un w), je n'avais pas de problème. En particulier l'affichage des objets de la classe A étaient conformes à mes attentes.

----------

## xaviermiller

alors, cherche de ce côté  :Wink: 

----------

## Magic Banana

J'ai eu de plus en plus l'impression que le problème est l'absence de constructeur de copie dans A. Ce tip allait par exemple aller dans ce sens.

Je l'ai ajouté (j'en ai aussi profité pour ajouter l'opérateur d'affectation mais ce n'était pas "vraiment" le problème et ne le mets donc pas ici) :

```
#include <vector>

class A

{

 public:

  A();

  A(int n);

  A(const A& otherA);

  std::vector<A*> v;

};
```

```
#include "A.h"

#include "B.h"

A::A()

{

}

A::A(const A& otherA)

{

  for (vector<A*>::const_iterator it = otherA.v.begin(); it != otherA.v.end(); ++it)

    {

      v.push_back(new A(**it));

    }

}

A::A(int n)

{

  if (n == 1)

    {

      v.push_back(new B());

    }

  else

    {

      v.push_back(new A(n-1));

    }

}
```

Visiblement l'ensemble constructeur par défaut + constructeur de copie + destructeur (que j'avais déjà en fait) + opérateur d'affectation s'appelle la forme canonique de Coplien (à ressortir en société  :Laughing:  ). Je copierai cent fois pour demain : "Il faut respecter la forme canonique de Coplien si ma classe a un attribut qui est un pointeur".  :Twisted Evil: 

----------

## xaviermiller

et voilà  :Wink: 

----------

