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

Avatar
Olivier Azeau
Benoît Bréholée wrote:
Encore faudrait-il que l'analogie soit pertinente. Ici, on pourrait
échanger "STL" et "allocation dynamique" pour faire une affirmation
tout aussi gratuite et complètement opposée sur le fond. Il faudrait
donc justifier en quoi cette analogie-là est correcte et pas
l'autre. Et comme l'a dit Gaby, c'est au mieux de l'illustration, pas
de l'argumentation.


Pour moi c'est ni l'un ni l'autre.
Je n'attends pas d'une analogie d'être "justifiée" mais c'est
probablement une question de perception individuelle.


Et en général, l'analogie sert à éclaircir quelque chose en comparant
à un sujet connu. Ici, le sujet connu c'est le C++, changer le
contexte ne simplifie pas les choses, bien au contraire, on y perd
beaucoup. Ce serait différent s'il s'agissait d'expliquer quelque
chose à un débutant (qui ne connaît donc pas le C++) et pour qui
l'analogie serait plus claire, mais on n'est pas dans ce cadre-là.


Un peu quand même non si on reprend le sujet initial du thread ?
Et même si certains interlocuteurs connaissent très bien le C++,
j'estime que cela peut au moins montrer comment "l'autre" perçoit les
choses.
C'est probablement là encore une question de perception individuelle.

Avatar
Olivier Azeau
Gabriel Dos Reis wrote:
Olivier Azeau writes:

| Gabriel Dos Reis wrote:
| > Olivier Azeau writes:
| > | Programmer en C++ sans se soucier du comment les choses sont
| > | organisées en mémoire, c'est utiliser le C++ comme du Java.
| > Pourquoi ?
|
| Parce qu'on ne s'inquiète alors pas de tout ce qui peut corrompre un
| pointeur et des conséquences que cela entraine.

Cela n'est pas du tout vrai. Je peux utiliser correctement (ainsi que
mes élèves) std::vector<> ou std::list<> sans me soucier de comment
les allocateurs marchent.


En fait mon affirmation n'est pas spécifique à STL : on est quand même
bien obligé d'utiliser directement des pointeurs à un moment ou à un
autre, non ?


| > | Programmer avec la STL sans maîtriser les templates, c'est la même
| > | chose : on ne maîtrise pas le comportement mémoire de ce que l'on
| > | utilise.
| > Pour quelles raisons ?
|
| Parce ce qu'on ne sait pas ce qui se passe sans une lecture
| hyper-attentive des docs et même quelquefois un petit saut dans le
| code source.

C'est un axiome ? Parce que des expériences grandeur nature montrent
quotidiennement le contraire.


Non, ce sont d'autres expériences grandeur nature.
Les 2 vérités ne sont pas forcément contradictoires : nous n'avons peut
être pas les moyens de nous attacher les services d'étudiants aussi bien
formés :-)

Je pencherais toutefois pour une différence de contexte : quand on me
signale un crash non reproductible en environnement de dev, que la seule
info dont je dispose est un offset dans une dll et qu'il me faut aller
chercher dans le code asm à quel pointeur du code source correspond
l'adressage causant une violation d'accès mémoire, je suis bien content
de connaître un minimum le fonctionnement bas niveau.


| Comment expliquer qu'il faut d'abord passer par un resize ou un
| push_back et qu'il vaut mieux utiliser at plutôt que [], tout ça sans
| aborder un minimum de gestion mémoire ?

Un tableau est une suite dynamique, i.e. dont le nombre d'éléments
varie au cours du programme et [] ne travaille que sur les eléments
dans le tableau. Tu peux en ajouter en faisant un push_back() -- qui
mettra l'élément à la fin.
Pourquoi vouloir insister sur la gestion manuelle ici pour expliquer
comment vector<> marche avec des opérations aussi simples ?

Parce que je trouve cette vision des choses inutile. Mais j'ai peut-être

mal digéré certains cours du même ton dans une vie antérieure :-)

Ce que je crois, c'est que ceux qui n'arrivent pas à dépasser cette
vision n'arriveront pas à faire pas du soft tel que je l'attends et que
ce qui la dépassent auraient de toutes façons compris une explication
immédiate plus pointue.

|
| J'ai du mal à cerner comment on peut évaluer la compréhension de la
| gestion mémoire dans un contexte de cursus universitaire.

Cela explique beaucoup de tes messages. Cela n'est pas parce que tu as
du mal à l'imaginer que cela ne se passe pas dans le concret.

Je n'ai pas de mal à l'imaginer, juste du mal à cerner le contenu.

Mais bon, je ne veux pas ouvrir un débat entre ce que l'on enseigne à
des étudiants et ce qu'ils auront besoin de savoir quand ils
travailleront. Je ne pense d'ailleurs pas avoir une vision suffisamment
large sur le sujet.

Olivier.

Avatar
Gabriel Dos Reis
Olivier Azeau writes:

| Gabriel Dos Reis wrote:
| > Olivier Azeau writes:
| > | Gabriel Dos Reis wrote:
| > | > Olivier Azeau writes:
| > | > | Programmer en C++ sans se soucier du comment les choses sont
| > | > | organisées en mémoire, c'est utiliser le C++ comme du Java.
| > | > Pourquoi ?
| > | | Parce qu'on ne s'inquiète alors pas de tout ce qui peut
| > corrompre un
| > | pointeur et des conséquences que cela entraine.
| > Cela n'est pas du tout vrai. Je peux utiliser correctement (ainsi que
| > mes élèves) std::vector<> ou std::list<> sans me soucier de comment
| > les allocateurs marchent.
|
| En fait mon affirmation n'est pas spécifique à STL : on est quand même
| bien obligé d'utiliser directement des pointeurs à un moment ou à un
| autre, non ?

Oui, mais la question est à quel moment est-ce approprié lorsqu'on
début en C++ ?
Tu sembles croire que l'apprentissage est un processus statique.

[...]

| > | Comment expliquer qu'il faut d'abord passer par un resize ou un
| > | push_back et qu'il vaut mieux utiliser at plutôt que [], tout ça sans
| > | aborder un minimum de gestion mémoire ?
| > Un tableau est une suite dynamique, i.e. dont le nombre d'éléments
| > varie au cours du programme et [] ne travaille que sur les eléments
| > dans le tableau. Tu peux en ajouter en faisant un push_back() -- qui
| > mettra l'élément à la fin. Pourquoi vouloir insister sur la gestion
| > manuelle ici pour expliquer
| > comment vector<> marche avec des opérations aussi simples ?
| >
| Parce que je trouve cette vision des choses inutile. Mais j'ai
| peut-être mal digéré certains cours du même ton dans une vie
| antérieure :-)
|
| Ce que je crois, c'est que ceux qui n'arrivent pas à dépasser cette
| vision n'arriveront pas à faire pas du soft tel que je l'attends et
| que ce qui la dépassent auraient de toutes façons compris une
| explication immédiate plus pointue.

Tu montres deux extrémités, mais tu passes sous silence ce qu'il y a
entre les deux. De fait, les expériences grandeur nature ici me
montrent que la vaste majorité de très loin s'en sort remaquablement
bien. Sans qu'ils aient besoin de savoir l'explication la plus avancée
tout de suite -- tant que l'explication du moment n'est pas un
mensonge ni une négation de ce qui se passe en réalité. En
progression, par niveau d'abstraction.

-- Gaby
Avatar
Loïc Joly
Olivier Azeau wrote:
Gabriel Dos Reis wrote:

Olivier Azeau writes:

| Gabriel Dos Reis wrote:
| > Olivier Azeau writes:
| > | Programmer en C++ sans se soucier du comment les choses sont
| > | organisées en mémoire, c'est utiliser le C++ comme du Java.
| > Pourquoi ?
| | Parce qu'on ne s'inquiète alors pas de tout ce qui peut corrompre un
| pointeur et des conséquences que cela entraine.

Cela n'est pas du tout vrai. Je peux utiliser correctement (ainsi que
mes élèves) std::vector<> ou std::list<> sans me soucier de comment
les allocateurs marchent.



En fait mon affirmation n'est pas spécifique à STL : on est quand même
bien obligé d'utiliser directement des pointeurs à un moment ou à un
autre, non ?


A un moment ou a un autre. Mais comme un des soucis de l'apprentissage
est de ne pas assomer tout de suite, mais d'introduire une certaine
progressivité, et comme il y a des choses qu'on ne peut pas faire après
la gestion de la mémoire, autant faire ces choses avant (par exemple :
Les fonctions, les notion de durée de vie, les structures de contrôle).
Et comme la STL permet d'illustrer ces notions aisément (plus que
l'allocation mémoire manuelle), autant l'introduire aussi avant cette
dernière.


| > | Programmer avec la STL sans maîtriser les templates, c'est la même
| > | chose : on ne maîtrise pas le comportement mémoire de ce que l'on
| > | utilise.
| > Pour quelles raisons ?
| | Parce ce qu'on ne sait pas ce qui se passe sans une lecture
| hyper-attentive des docs et même quelquefois un petit saut dans le
| code source.




Faut-il comprendre comment fonctionne cout pour faire un "Hello world!"
? Si oui, j'ai peur qu'un "Hello world!" ne soit pas vraiment un bon
programme pour débutant, puisqu'il met en oeuvre surcharge d'opérateurs,
polymorphisme, templates, surcharge de fonction, traits, espace
référentiel, exceptions...

--
Loïc


Avatar
Richard Delorme
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.


Je ne trouve pas. En Java, les objets sont toujours manipulés par des
référence, et dans ton exemple C++ tu utilises des objets créés en
mémoire automatique et en plus tu les passes par valeur plutôt que par
référence. Il s'agit donc d'une situation inexistente en Java, et je
comprends mal comment en déduire le fonctionnement de ton programme à
partir de fonctionnalités inexistentes du langage Java.


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.


J'ai l'impression que tu supposes que quelqu'un qui connaît Java et
connaît ou va apprendre le C++ va volontairement ignorer les différences
entre les deux langages. Je ne crois pas. Quand on passe d'un langage à
l'autre on s'attache particulièrement à en apprendre les différences.

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


Depuis quand la bibliothèque standard du C++ ne fait plus 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.


Je ne suis pas d'accord avec ton analogie. La bibliothèque standard
fourmille d'outils qui accélèrent et sécurisent la programmation en C++.
Ne pas les utiliser, c'est comme bricoler son propre régulateur de
vitesse soi-même plutôt que d'utiliser celui du constructeur, et le
résultat sera souvent plus catastrophique.

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


Ben justement, l'utilisation des containers de la bibliothèque standard
limite énormément les problèmes de corruption de mémoire, d'après ma
propre expérience.

--
Richard



Avatar
Loïc Joly
Olivier Azeau wrote:
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);
}


Ce genre de question piège pour mauvais élève ne me gêne pas. Ce qui me
gêne plus, c'est de voir du code du style :

class math
{
public:
static double sin(double x);
};

Ou encore plus courant :

class A
{ // ...
};

int main()
{
A *a = new A;
delete a;
}

Au lieu de :
int main()
{
A a;
}

--
Loïc

Avatar
Gabriel Dos Reis
Loïc Joly writes:

| int main()
| {
| A *a = new A;
| delete a;
| }

Celle-là, elle me tue :-(

-- Gaby
Avatar
Olivier Azeau
Loïc Joly wrote:
Olivier Azeau wrote:
En fait mon affirmation n'est pas spécifique à STL : on est quand même
bien obligé d'utiliser directement des pointeurs à un moment ou à un
autre, non ?


A un moment ou a un autre. Mais comme un des soucis de l'apprentissage
est de ne pas assomer tout de suite, mais d'introduire une certaine
progressivité, et comme il y a des choses qu'on ne peut pas faire après
la gestion de la mémoire, autant faire ces choses avant (par exemple :
Les fonctions, les notion de durée de vie, les structures de contrôle).
Et comme la STL permet d'illustrer ces notions aisément (plus que
l'allocation mémoire manuelle), autant l'introduire aussi avant cette
dernière.

Note en passant : de mon pt de vue la notion de durée de vie, c'est de

la gestion de la mémoire.

Bien sûr que le processus n'est pas statique et qu'il y a forcément
progressivité mais on peut quand même se demander si cette progression
est la bonne.
J'ai eu la "chance" de connaître d'abord le C et d'apprendre la POO avec
Eiffel. J'ai découvert ensuite le C++ comme un croisement entre ces 2
mondes. Ce qui semble me gêner, en fait, c'est un apprentissage du C++
similaire à celui que j'ai connu avec Eiffel : celui d'un langage
empreint d'une certaine "pureté" vis à vis de la programmation objet.

Gabriel semble vérifier que cela fonctionne avec les étudiants mais je
garderai tout de même un doute sur l'efficacité de la méthode quand il
s'agit de l'appliquer à un contexte où la réalité du C++ est quand même
plus proche d'un "C avec classes et templates".


| > | Programmer avec la STL sans maîtriser les templates, c'est la même
| > | chose : on ne maîtrise pas le comportement mémoire de ce que l'on
| > | utilise.
| > Pour quelles raisons ?
| | Parce ce qu'on ne sait pas ce qui se passe sans une lecture
| hyper-attentive des docs et même quelquefois un petit saut dans le
| code source.





Faut-il comprendre comment fonctionne cout pour faire un "Hello world!"
? Si oui, j'ai peur qu'un "Hello world!" ne soit pas vraiment un bon
programme pour débutant, puisqu'il met en oeuvre surcharge d'opérateurs,
polymorphisme, templates, surcharge de fonction, traits, espace
référentiel, exceptions...

A-t-on besoin d'un cout pour faire un "Hello world!" ? :-)




Avatar
Olivier Azeau
Richard Delorme wrote:

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.



Je ne trouve pas. En Java, les objets sont toujours manipulés par des
référence, et dans ton exemple C++ tu utilises des objets créés en
mémoire automatique et en plus tu les passes par valeur plutôt que par
référence. Il s'agit donc d'une situation inexistente en Java, et je
comprends mal comment en déduire le fonctionnement de ton programme à
partir de fonctionnalités inexistentes du langage Java.

Ben moi aussi je comprends mal comment on peut le déduire mais le

problème c'est je vois malheureusement trop de gens qui y arrivent sans
sourciller et qui font n'importe quoi !!!

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



Depuis quand la bibliothèque standard du C++ ne fait plus partie du
langage ?


Grand débat sur la définition de "langage" (mots-clefs + sémantique +
idiomes + librairie + etc. )
C'est pour cela que j'avais déja mis des guillemets.
Je veux simplement dire qu'un "dialecte" du C++ n'incluant pas la STL
est parfaitement viable, et, de mon point de vue, plus simple à appréhender.



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.



Je ne suis pas d'accord avec ton analogie. La bibliothèque standard
fourmille d'outils qui accélèrent et sécurisent la programmation en C++.
Ne pas les utiliser, c'est comme bricoler son propre régulateur de
vitesse soi-même plutôt que d'utiliser celui du constructeur, et le
résultat sera souvent plus catastrophique.

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



Ben justement, l'utilisation des containers de la bibliothèque standard
limite énormément les problèmes de corruption de mémoire, d'après ma
propre expérience.

Ok. Toujours le même pb : à condition de bien les utiliser.



Avatar
Gabriel Dos Reis
Olivier Azeau writes:

| Loïc Joly wrote:
| > Olivier Azeau wrote:
| >> En fait mon affirmation n'est pas spécifique à STL : on est quand
| >> même bien obligé d'utiliser directement des pointeurs à un moment
| >> ou à un autre, non ?
| > A un moment ou a un autre. Mais comme un des soucis de
| > l'apprentissage est de ne pas assomer tout de suite, mais
| > d'introduire une certaine progressivité, et comme il y a des choses
| > qu'on ne peut pas faire après la gestion de la mémoire, autant faire
| > ces choses avant (par exemple : Les fonctions, les notion de durée
| > de vie, les structures de contrôle). Et comme la STL permet
| > d'illustrer ces notions aisément (plus que l'allocation mémoire
| > manuelle), autant l'introduire aussi avant cette dernière.
| >
| Note en passant : de mon pt de vue la notion de durée de vie, c'est de
| la gestion de la mémoire.

Je plains tes élèves ou ceux à qui tu dois enseigner C++.

| Bien sûr que le processus n'est pas statique et qu'il y a forcément
| progressivité mais on peut quand même se demander si cette progression
| est la bonne.
| J'ai eu la "chance" de connaître d'abord le C et d'apprendre la POO
| avec Eiffel.

J'aurais dû m'en douter.

| J'ai découvert ensuite le C++ comme un croisement entre
| ces 2 mondes. Ce qui semble me gêner, en fait, c'est un apprentissage
| du C++ similaire à celui que j'ai connu avec Eiffel : celui d'un
| langage empreint d'une certaine "pureté" vis à vis de la programmation
| objet.
|
| Gabriel semble vérifier que cela fonctionne avec les étudiants mais je
| garderai tout de même un doute sur l'efficacité de la méthode quand il
| s'agit de l'appliquer à un contexte où la réalité du C++ est quand
| même plus proche d'un "C avec classes et templates".

Comme je l'ai dit d;ans un autre message, j'ai vérifié la chose dans
nombres occasion, en commençant par des programmeurs qui ne
connaissent que C et l'assembleur. D'autres sont même vierges en
matière de programation.

-- Gaby