OVH Cloud OVH Cloud

[Debutant] Probleme de destruction

120 réponses
Avatar
Yoxoman
Bonjour à tous.

Je me permet de vous soumettre ce petit programme, qui représente en
gros la partie qui me pose problème d'un truc plus gros :

#include <iostream>

using namespace std;

class Vecteur
{
public:
double *val;
int taille;

Vecteur() {}
Vecteur(int i);
~Vecteur() {cout << "detruit" << endl; delete[] val;}

Vecteur foisDeux();
Vecteur &operator=(const Vecteur &v);
};

Vecteur::Vecteur(int i)
{
taille=i;
val=new double[i];
}

Vecteur Vecteur::foisDeux()
{
Vecteur temp(taille);

for (int i=0; i<taille; i++)
{
temp.val[i]=2*val[i];
}

return temp; //(1)
}

Vecteur &Vecteur::operator=(const Vecteur &v)
{
taille=v.taille;
val=new double[taille];

for (int i=0; i<taille; i++)
{
val[i]=v.val[i];
}

return *this;
}

int main(void)
{
Vecteur v1(3);
Vecteur v2;

v2=v1.foisDeux(); //(2)

return 0;
}

Segmentation fault.
J'ai tout d'abord eu du mal à identifier le problème, mais j'ai réussi
grâce à des supers pouvoirs hérités de Goldorak.
En fait, à la fin de la fonction foisDeux(), la variable temporaire
temp est détruite. Logique. En même temps, la fonction renvoie une
copie de l'objet, qui possède donc dans ses attributs un pointeur sur
une zone mémoire inaccessible (action du delete[]). Problème donc à la
destruction de ce dernier.

En fait, je ne sais pas trop comment arranger ce problème. Je ne
voudrais pas modifier *directement* les attributs de v1 dans la
fonction foisDeux(), pour garder ce vecteur en stock.

Merci d'avance pour votre aide.

10 réponses

1 2 3 4 5
Avatar
Olivier Azeau
Gabriel Dos Reis wrote:
Olivier Azeau writes:
| Apprendre à se servir des templates et de la STL ? C'est ça les bases ?

Apprendre à se servir de la bilbiothèque standard. Oui. On n'a besoin
d'aucun talent particulier des templates.



Ouais... C'est avec des arguments comme ça que les auto-écoles vont
apprendre à faire les créneaux avec un radar de recul sous prétexte que
c'est en "standard" sur les voitures.

Cela n'a pas grand sens de se lancer dans la conception d'une classe,
quand on ne connaît pas les outils fondamentaux 101.
Ah, c'est vrai j'oubliais il y a encore un certain nombre de gens qui
pensent que C++ doit s'apprendre ou s'enseigner comme eux ils l'ont
appirs il y a plus d'une décennie, alors le langage d'aujourd'hui est
vachement différent. CIl ne reste plus qu'à espérer que la promotion
naturelle les sortira de la circulation, le plus rapidement possible.



D'ailleurs nombre d'entre eux sont déjà sortis du dev C++ : maintenant
ils ne font que recruter et superviser les développeurs...
Malheureusement, ils le font avec leurs propres critères et sont souvent
desespérés de voir le nombre de développeurs qui se comportent avec le
C++ comme si c'était du Java...

Avatar
Yoxoman

Vecteur &Vecteur::operator=(const Vecteur &v)
{
taille=v.taille;
val=new double[taille];

for (int i=0; i<taille; i++)
{
val[i]=v.val[i];
}

return *this;
}



int main(void)
{
Vecteur v1(3);
Vecteur v2;

v2=v1.foisDeux(); //(2)

return 0;
}

Aucun destructeur n'est appelé quand on fait "Vecteur x,y; x = y;"


Certes.

Lors du "x=y" le x.val reçoit un "new double[taille]" qui écrase le
x.val alloué dans le constructeur par défaut sans faire le "delete []"
correspondant.


Mais le constructeur par défaut n'alloue pas de mémoire pour le
pointeur val. Il en serait bien incapable, vu qu'on ne lui donne pas la
taille du vecteur. Dans mon cas, v2 est juste construit avec un
pointeur qui ne pointe sur rien de particulier, donc faire un delete[]
serait une faute.

Non ?

Avatar
Richard Delorme

Malheureusement, ils le font avec leurs propres critères et sont souvent
desespérés de voir le nombre de développeurs qui se comportent avec le
C++ comme si c'était du Java...


Java et C++ sont si différent que j'ai du mal à voir comment cela est
possible. Puis-je avoir des détails ?

--
Richard

Avatar
Yoxoman

Mais le constructeur par défaut n'alloue pas de mémoire pour le
pointeur val. Il en serait bien incapable, vu qu'on ne lui donne pas la
taille du vecteur. Dans mon cas, v2 est juste construit avec un
pointeur qui ne pointe sur rien de particulier, donc faire un delete[]
serait une faute.


Cependant, et dans l'hypothèse où je ne raconte pas de grosses
conneries, il est vrai qu'il faudrait peut-être mettre un delete[] dans
l'operateur d'affectation, dans le cas où le vecteur affecté a été
initialisé avec le constructeur Vecteur(int).
Je pourrais juste faire un {val=NULL;} dans le constructeur par défaut.

C'est correct ?

Avatar
Olivier Azeau
Yoxoman wrote:

int main(void)
{
Vecteur v1(3);
Vecteur v2;

v2=v1.foisDeux(); //(2)

return 0;
}


Mais le constructeur par défaut n'alloue pas de mémoire pour le
pointeur val. Il en serait bien incapable, vu qu'on ne lui donne pas la
taille du vecteur. Dans mon cas, v2 est juste construit avec un
pointeur qui ne pointe sur rien de particulier, donc faire un delete[]
serait une faute.

Non ?



Tu as raison. Autant pour moi. J'ai lu un peu trop vite.

Il n'en reste pas moins que le constructeur qui prend un int en
paramètre alloue de la mémoire
Donc si j'écris par exemple :

int main(void)
{
Vecteur v1(3);
Vecteur v2(5);

v2=v1.foisDeux();

return 0;
}

Il y a une perte au niveau du vecteur v2 lors de l'affectation.

Par ailleurs, créer un vecteur "qui ne pointe sur rien" est en soi assez
risqué : il est toujours préférable de l'initialiser avec le pointeur null.

D'ailleurs, dans le destructeur tu vas de toutes façons appeler un
"delete []" sur ce pointeur qui ne pointe sur rien donc tu auras le
problème à ce moment là.

Pour rappel, appeler delete sur un pointeur null est une opération tout
à fait valide qui en fait ne fait rien (pas besoin de tester la nullité
du pointeur).

Avatar
Yoxoman

(...) Pour rappel, appeler delete sur un pointeur null est une opération tout
à fait valide qui en fait ne fait rien (pas besoin de tester la nullité
du pointeur).


Merci beaucoup pour toutes ces informations.

Avatar
Olivier Azeau
Richard Delorme wrote:

Malheureusement, ils le font avec leurs propres critères et sont
souvent desespérés de voir le nombre de développeurs qui se comportent
avec le C++ comme si c'était du Java...



Java et C++ sont si différent que j'ai du mal à voir comment cela est
possible. Puis-je avoir des détails ?



Il suffit de demander à un frais émoulu de l'école, où il a fait pas mal
de Java et un peu de C++, ce qu'affiche ce programme (et pourquoi) :

----------------------------
class A
{
public: virtual void f() { cout << "A::f" << endl; }
};

class B : public A
{
public: virtual void f() { cout << "B::f" << endl; }
};

void g(A a) { a.f(); }

void main()
{
B b;
g(b);
}
----------------------------

Le problème c'est que Java et C++ sont par essence très différents mais
qu'ils sont aussi par ailleurs horriblement proches d'un point de vue
syntaxique. Il est donc aisé d'induire le comportement de l'un par ce
que l'on connait de l'autre.

Un développeur qui connait pas trop mal Java et qui se met au C++ ça
ressemble un peu à un qqun qui a appris à conduire avec une boite
automatique et se met à conduire avec une boite manuelle : il connait le
volant, l'accélérateur et le frein mais s'il reste en 1ère, il n'ira pas
bien loin.

C'est pour cela que je trouve dangereux d'apprendre le C++ avec toute la
STL comme "faisant partie du langage".
La STL est au C++, ce que le régulateur de vitesse automatique est à la
conduite : un fabuleux outil pour celui qui le maîtrise et un bon moyen
de finir dans le décor pour les autres.

Que celui qui n'a jamais eu à désembrouiller des problèmes de corruption
mémoire en C++ me jette la première pierre...

Olivier.

PS : désolé pour mes analogies automobiles, ce sont les seules qui me
viennent à l'esprit


Avatar
Gabriel Dos Reis
Olivier Azeau writes:

| Gabriel Dos Reis wrote:
| > Olivier Azeau writes:
| > | Apprendre à se servir des templates et de la STL ? C'est ça les bases ?
| > Apprendre à se servir de la bilbiothèque standard. Oui. On n'a besoin
| > d'aucun talent particulier des templates.
|
| Ouais... C'est avec des arguments comme ça que les auto-écoles vont
| apprendre à faire les créneaux avec un radar de recul sous prétexte
| que c'est en "standard" sur les voitures.

Nous sommes en train de discuter de l'apprentissage de C++ et non
d'auto-ecole, n'est-ce pas ? Te serais-tu gouré de newsgroupe ?

-- Gaby
Avatar
Gabriel Dos Reis
Olivier Azeau writes:

| Olivier.
|
| PS : désolé pour mes analogies automobiles, ce sont les seules qui me
| viennent à l'esprit

Proof by analogy os frwaud, comme c'est connu dans la communauté C++.

-- Gaby
Avatar
Gabriel Dos Reis
Olivier Azeau writes:

| C'est pour cela que je trouve dangereux d'apprendre le C++ avec toute
| la STL comme "faisant partie du langage".

Personne ne dit de n'apprendre _que_ la STL, mais d'avoir d'abord une
idée un peu claire sur les B A BA. Tu en déduis qu'il ne faut que le B
A BA.

| La STL est au C++, ce que le régulateur de vitesse automatique est à
| la conduite : un fabuleux outil pour celui qui le maîtrise et un bon
| moyen de finir dans le décor pour les autres.

Proof by analgy is fraud.

-- Gaby
1 2 3 4 5