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
Gabriel Dos Reis
"Alain Naigeon" writes:

| [réponse à Gaby, à propos de "mauvais chefs de projets"]
|
| En fait, malgré l'heure tardive, je viens de chercher quand même,
| et je retrouve ceci :
|
| "Gabriel Dos Reis" a écrit dans le message
| news:
| > Olivier Azeau writes:
| >
| > | Gabriel Dos Reis wrote:
| > | > Olivier Azeau writes:
| > | > | Mais tu fais quoi quand tu as une librairie tierce qui ne te
| > | > propose
| > | > | que des factories qui créent dans le tas et que tu n'as besoin de
| > | > | l'objet que le temps d'un appel de fonction ?
| > | > Mauvais fournisseur, changer de fournisseur. Ou, si la chose est
| > | > important pour le projet, investir dedans. Si ce n'est pas important
| > | > pour le projet, ...
| > | >
| > | Oui, c'est beau la théorie...
| >
| > Je parle de la pratique et non une théorie. En fait, une pratique que
| > j'ai vécue plusisurs fois. Si la chose est importante pour le projet,
| > on y investit.
| > Mais je ne nie pas l'existance de mauvais managers, dans ce cas c'est
| > le manager qu'il faut blâmer.
|
| Il semble pour cette fois je gagne le tie-break - sauf si tu refuses que
| l'on
| traduise "[project] manager" par chef de projet !

Pardon ?

-- Gaby
Avatar
Gabriel Dos Reis
"Alain Naigeon" writes:

| "Gabriel Dos Reis" a écrit dans le message
| news:
| > "Alain Naigeon" writes:
| > | entendre "tu as tort parce que tu es moins bon que moi", tu vois, ça ne
| > | convaincra jamais.
| >
| > Je t'ai dit ça ?
|
| Oui, tu as dis que certainement des aspects pointus m'échapperaient
| si tu me soumettais donnais un exemple de ce genre à résoudre (ce
| que je ne nie pas).

Pardon ? Tu sembles vivre sur uen autre planète.

-- Gaby
Avatar
Olivier Azeau
Gabriel Dos Reis wrote:
"Alain Naigeon" writes:
| Il y a autre chose : je n'ai pas pris l'initiave de reprendre ce débat ; il
| se
| trouve que, cette fois-ci, c'est quelqu'un (Olivier) qui, à vue de nez, a
| une expérience, y compris professionnelle. Peut-être même est-il chef
| de projet (?), et je me demande si ce n'était ton secret espoir quand
| tu as balancé une remarque sur les mauvais chefs de projets ;-)

Pardon ? Là, je ne te suis pas du tout. Toute explication que tu
approterais dans ce sens serait la bienvenue -- à moins bien sûr, que
tu ne retractes encore ton affirmation (ce qui deviendrait comme une
ennuyeuse habitude).



Il se trouve que j'ai un instant envisagé le même raisonnement qu'Alain.
Comme quoi il y existe des fois où l'on tombe juste sans forcément le
faire exprès...
J'espère que ce n'est pas trop souvent le cas quand on choisit une façon
d'enseigner le C++ :-)

| Alors bon, je suis sûr que ton expérience d'enseignement est positive,
| mais toi tu sembles avoir du mal à admettre que d'autres fonctionnent
| aussi.

Mais pas du tout. Je veux simplement voir ces autres approches
marcher. Ce que je dis, c'est que j'ai trop vu en pratique les
approches dont il était question mener à un résultat déplorable.
Je veux bien croire que c'est une constation unique. Mais lorsque je
regarde les approches pris des bouquins récents comme ceux de
Koenig&Moo, je me dis que ce n'est pas un phénomène local. J'ai aussi
lu des revues de ces bouquins qui enseignent le C++ comme si c'était
juste le C avec le mot clé « class ». Ce que je te propose, c'est de
regarder les données concrètes.



Le problème c'est que chacun a les données concrètes qui sont
pertinentes pour son propre contexte.
Je vois pour ma part des personnes qui connaissent des langages évolués,
dont le C++, et qui savent faire des bons trucs mais, quand on gratte la
surface pour aller sur un comportement plus bas niveau, il n'y a plus
personne.
Je ne critique pas telle ou telle approche éducative : je dis juste que,
pour *mon contexte*, les pointeurs *c'est la base* et que celui qui ne
maîtrise pas ça, il ne maîtrise rien.
C'est pour cela que j'ai, légitimement je pense, un peu "peur" quand on
veut faire passer le C++ pour un langage de haut-niveau : dans beaucoup
de contextes, même si on essaie de faire évoluer les choses, cela n'est
pas la réalité quotidienne.

J'ai l'impression qu'avec une telle approche on va rapidement en arriver
(si ce n'est déjà fait) à commencer par enseigner Loki pour découvrir
des patterns fabrique ou visiteur sous prétexte que c'est plus haut
niveau et que l'on pourra voir les détails ensuite...
Et là il y aura des "vieux réacs" pour avoir l'impression que l'on
apprend à qqun à conduire une voiture en le mettant aux commandes d'une
Formule 1.

Avatar
Loïc Joly
Olivier Azeau wrote:

C'est exactement ce qui me gêne : "les apprendre plus tard".
Si j'apprends avec un radar de recul, qu'est ce qui va me motiver pour
*ensuite* apprendre sans ?
Pareil pour les pointeurs : personne ne me fera écrire une classe string
à la main si qqun d'autre m'a déja montré std::string


Non, et c'est très bien. Par contre, quand on te montrera comment
utiliser un schmurtzHandle* manuellement, tu n'auras qu'une envie :
Créer une classe Schmurtz, qui sera à un schmurtzHandle* ce que
std::string est à char *.

Et donc tu apprendras à faire ce genre de classe, mais en plus, tu auras
un exemple pour te guider dans tes choix.

--
Loïc

Avatar
K. Ahausse
"Alain Naigeon" a écrit dans le message de
news:41be4c7d$0$25277$

Je ne comprends plus rien, c'est trop retords pour moi.


Houlala, tu t'es perdu dans tes propres méandres ( depuis un bon bout déjà)
Tu insistes, et persistes : accuser ton interlocuteur de tes PROPRES
défauts.

Dans le brouillard où je suis, essayant de te comprendre,


"te comprendre" ?
Je dirais plutot : comprendre comment te prendre en défaut, obstinament.

je ne sais si cette remarque aura la
moindre pertinence : j'ai poursuivi la discussion car cet argument n'était
pas
le seul, la discussion avec toi et d'autres étant intéressante sur ce
point,

ce n'était
pas une raison suffisante pour l'arrêter : le simple fait que tu n'aie pas
utilisé l'argument
ne voulait évidement pas dire que tu as avais changé de position.



| Je te crédite (donc) d'une totale bonne foi, et c'est ça qui te pose
| problème ?

non, ce qui me pose problème, c'est ton incohérence.

| Je trouve que tu réponds souvent par des pirouettes (comme ce "donc"),
| et ce n'est pas la meilleure façon de rester bien installé entre ton
clavier

| et ton écran ;-)

si prendre quelqu'un en flagrant délit d'incohérence est ce que tu
considères une pirouette alors je suis bien installé dans entre mon
clavier et mon écrna. Merci.


Bah tu sais, la cohérence peut aussi fonctionner comme une médaille,
sans rapport, parfois, avec ce qu'on est vraiment. Regarde un fil qui
vient

de parler, une fois de plus, de garbage collector. Moi qui, dans une
certaine
mesure, comprends et aime les pointeurs, eh bien, j'aimerais bien que le
langage propose (facultativement) un GC. Incohérence ? Par ailleurs, je


Une incohérence est de voir surgir, dont ne sait où, un GC.

D'une personne aussi intelligente, se fourvoyer autant amène à la réflexion.

suis sûr que parmi les tenants de ta thèse concernant l'apprentissage
retardé
des pointeurs, il y a des gens farouchement opposés au GC. Incohérence ?
En fait je ne crois pas. Chaque partie accorde un poids différent au GC,
selon
son habitude des pointeurs et de ce qu'ils apportent. (comment faire une
liste
chaînée sans pointeurs ?) En oubliant le prix à payer de s'en passer, à
savoir
une certaine proportion d'erreurs de destruction. Mais les gens qui
manipulent
les pointeurs sont donc bien envie d'éviter cette gestion fastidieuse et
parfois
difficile carrément (notamment quand plusieurs objets sont confiés à
plusieurs
containers). Par conséquent, l'incohérence n'est qu'apparente, dans le cas
d'un GC facultatif : on gère tous les standard qui éviteront bien des
bévues

ou oublis, et l'on garde la possibilité de gerer soi-même les cas
particuliers
qu'on juge néfaste de leur confier (dans mon esprit un bon GC doit être
facultatif jusqu'au point de permettre de lui confier seulement certains
pointeurs ou types de pointeurs, les autres étant toujours gérés à la
main)

Moi j'ai fait une hastable template instanciée par le type du pointeur,
détruite en fin de programme. On lui confiait un pointeur par > on en
redevenait propriétaire par < Mais on peut aussi à tout moment lui
demander la destruction de l'objet pointé par un pointeur quelle possède,
et alors elle remet à zero ce pointeur qui pourrait être utilisé à tort
par

l'appelant si quelques lignes plus loin il a oublié la destruction.
L'idée à la base, c'est de régler un certains de motifs d'erreurs
fréquentes,
mais sans pénaliser l'occupation mémoire qui serait inacceptable dans
certains
cas si tous les pointeurs devaient rester intacts jusqu'à la fin de
l'exécution.
Quand la fin d'une étape rend inutile tous les objets concernés, eh bien,
il suffit d'avoir alloué statiquement le GC pour ce type au début d'un
bloc,

donc en sortie de bloc le GC détruit tout ce qui ne l'aurait pas été
explicitement
entre-temps. C'est simple, ça marche bien, mais évidemment ça necessite
une coopération honnête du code source (comme approche facultative,
il me semble).


J'ai essayé mais je n'ai pas saisi le lien avec la conversation.
Je comprends : tentative de noyer le poisson avec, dans un premier temps,
l'incohérence apparente, enchainée avec ta virtuosité dans le maniement des
pointeurs.


Avatar
kanze
Luc Hermitte wrote:
wrote in
news::

Il veut dire que si ton opérateur d'affectation est
exception-safe,


il va prèsque sûrement fonctionner correctement dans le cas
d'affectation sur lui-même, sans test particulier. Alors, le test
est un comparison de plus ; c'est une optimisation si on affecte
souvent à soi-même, mais une pessimisation dans les autres cas.


Oui.

<petite parenthèse>

Si on est concerné par la question de la vitesse, AMHA, la
première


chose à faire serait de supprimer l'allocation si la destination a
déjà la bonne taille, c-à-d quelque chose du genre :

double * newval =
( taille == other.taille ? val : new double[ other.taille ] ) ;
std::copy( other.val, other.val + other.taille, newval ) ;
if ( newval != val ) delete [] val ;
val = newval ;
taille = other.taille ;
return *this ;


Dans ce cas particulier où l'on gère des doubles c'est OK. Dans le
cas

plus générique où l'on pourrait avoir un vecteur de n'importe
quoi, et

en particulier des choses dont les copies peuvent lever des
exceptions, cette méthode n'est plus bonne dans la mesure où elle
invaliderait l'objet que l'on tentait de modifer, si une exception
apparait durant le std::copy.


Ah bon. Il me semble que si l'opérateur d'affectation de l'object est
lui-même exception-safe, le tableau restera valid. On ne saurait pas
exactement ce qu'il contient, mais typiquement, ça ne fait rien, parce
qu'il serait de toute façon detruite lors du nettoyage de la pile.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
kanze
Alain Naigeon wrote:
a écrit dans le message news:


Et comme j'ai déjà dit par ailleurs, apprendre à conduire avec une
boîte automatique avant de conduire avec une boîte manuelle n'est
pas

forcement une mauvaise politique.

*pas forcément*, ok, voilà une expression méritoire et nécessaire
!

J'ai l'impression qu'aux USA on est absolument convaincu qu'on ne
peut

s'en sortir avec une boîte manuelle, et ça n'empêche pas des
centaines

de millions d'Européens de conduire ainsi tous les jours.


En quoi est-ce que ça a un rapport avec ce qu'on dit. On ne dit pas de
n'apprendre que la boîte automatique. Ce qu'on suggère, c'est :

- D'abord familiariser l'élève avec la conduite en général,
l'utilisation du volant, etc. Avec une boîte automatique, et sans
s'attaquer aux créneaux.

- Ensuite, l'apprendre l'utilisation d'une boîte manuelle.

- Et enfin, une fois que l'élève a maîtrisé tout ça, de
s'attaquer aux
crénaux.

Mais évidemment, je suis d'avis qu'il ne faut pas donner un permis de
conduire jusqu'à ce que l'élève a tout maîtrisé. (Encore qu'en
Allemagne, et probablement en France, il est possible de faire un
permis
« à boîte automatique seulement ». C'est prévu, par exemple, pour
des
handicappés qui ne peuvent se servir que d'une main ou d'une jambe.)

En C++, ça devient :

- D'abord familiariser l'élève avec la programmation en C+ en
général,
comment écrire une conditionnelle ou une boucle, déclarer une
variable, etc. Pour l'apprentissage de la boucle, pouvoir déclarer
un tableau est intéressant, donc, std::vector.

- Ensuite, passe à des choses essentielles à une utilisation
pratique,
comme la définition des classes, voire même l'écriture des
templates
simples.

- Et enfin, s'attaquer à des choses qu'il faut bien savoir, mais qui
ne sert pas à chaque instant, et qui sont nettement plus
compliquées, comme les pointeurs.

[...]
(ce n'était pas une réponse de James, qui, je crois, a une position
plus nuancée, c'était une réponse de Gaby, entre autres - l'argu-
ment

est revenu plus d'une fois. Quoiqu'il en soit, sur usenet en
général,

et sur ce groupe, je réagis à des idées, pas à des personnes).


Je n'ai pas vu où Gaby disait qu'il ne fallait jamais enseigner les
pointeurs. Simplement qu'il fallait faire des choses dans l'ordre, et
ne
pas noyer l'élève avec des complexités inutiles avant qu'il se sont
comfortable avec les bases du langage. Mais mon impression de ce qu'il
disait était qu'il fallait bien connaître tout le C++ avant la fin du
cours. L'argument touchait uniquement l'ordre de la présentation -- je
n'ai vu personne suggérait qu'il ne fallait pas enseigner des
pointeurs
(ni qu'il ne fallait pas enseigner la STL) du tout.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
kanze
Olivier Azeau wrote:
wrote:
Olivier Azeau wrote:

Gabriel Dos Reis wrote:
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.


Analogie, il me semble, serait plutôt des auto-écoles qui
apprendre


à démarrer la voiture, et de la faire avancer à la vitesse
voulue en


ligne droite, avant de apprendre à faire des créneaux en marche
en


arrière.

En ce qui concerne ton analogie, elle a plusieurs défauts :

- Les radars de recul ne sont pas standard. Il existe bien des
voitures qui ne les ont pas. Tandis que std::vector et
std::string


font bien partie de C++ -- s'ils ne sont pas présents, ce n'est
pas du C++.


Oui, d'où ma conjugaison au futur (qui j'espère est un futur
hypothétique)


Pourquoi hypothétique ? Juste parce que la voiture de mon grand-père
ne
l'avait pas ? Ça me semble une amélioration « compatbile » avec
l'existante -- si un jour, toutes les voitures l'ont, ceux qui ont
appris avant à faire sans pourrait encore faire comme avant.

- Apprendre d'abord à faire des créneaux avec le radar de recul,
puis ensuite sans, ne serait peut-être pas une mauvaise idée.
Si


on ne l'a pas essayée encore, c'est sans doute que les radar de
recul sont encore assez rare. Il n'est pas question que les
élèves


n'apprenent jamais des pointeurs. Seulement qu'ils les apprenent
plus tard, quand ils ont déjà maîtriser des choses plus
simples.



C'est exactement ce qui me gêne : "les apprendre plus tard". Si
j'apprends avec un radar de recul, qu'est ce qui va me motiver pour
*ensuite* apprendre sans ?


Le fait que tu n'aurais pas le permis sans l'apprendre. Le fait qu'il y
a encore beaucoup de voitures qui ne l'ont pas. (Aux États-unis, il y
a
beaucoup de monde qui apprend à conduire sans jamais toucher à une
boîte
manuelle. Et ils en sortent très bien, aux États-unis.)

Pareil pour les pointeurs : personne ne me fera écrire une classe
string à la main si qqun d'autre m'a déja montré std::string


Ça dépend. D'abord, évidemment, s'il leur faut implémenter une
classe
string pour avoir le crédit pour le cours, ils vont le faire. Mais
encore plus fondamental, il existe bien certaines choses où les
pointeurs sont nécessaires : est-ce que tu penses que même aux
États-unis, les gens se passeraient d'apprendre la boîte manuelle si
on
ne pouvait pas dépasser 40 mph sans s'en servir ?

Un autre aspect est le but de l'enseignement. Écrire une classe vector
vraiment robuste, c'est l'affaire d'un expert. Exiger que quelqu'un
l'apprend pour dire qu'il a appris le C++, c'est un peu comme exiger
que
quelqu'un sache règler un carburateur pour dire qu'il sait conduire
une
voiture. Si la bibliothèque standard couvrait tout ce qu'on peut faire
avec des pointeurs, et qu'on n'avait pas réelement besoin des
pointeurs
dans la programmation applicative, je dirais qu'on pourrait se passer
d'enseigner des pointeurs. Ce n'est pas le cas pour les pointeurs, mais
c'est peut-être le cas pour certaines autres techniques avancées.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
Luc Hermitte
wrote in news:1103017263.964491.104460
@f14g2000cwb.googlegroups.com:

<petite parenthèse>

Si on est concerné par la question de la vitesse, AMHA, la première
chose à faire serait de supprimer l'allocation si la destination a
déjà la bonne taille, c-à-d quelque chose du genre :

double * newval >> > ( taille == other.taille ? val : new double[ other.taille ] ) ;
std::copy( other.val, other.val + other.taille, newval ) ;
if ( newval != val ) delete [] val ;
val = newval ;
taille = other.taille ; return *this ;


Dans ce cas particulier où l'on gère des doubles c'est OK. Dans le cas
plus générique où l'on pourrait avoir un vecteur de n'importe quoi, et
en particulier des choses dont les copies peuvent lever des
exceptions, cette méthode n'est plus bonne dans la mesure où elle
invaliderait l'objet que l'on tentait de modifer, si une exception
apparait durant le std::copy.


Ah bon. Il me semble que si l'opérateur d'affectation de l'object est
lui-même exception-safe, le tableau restera valid. On ne saurait pas
exactement ce qu'il contient, mais typiquement, ça ne fait rien, parce
qu'il serait de toute façon detruite lors du nettoyage de la pile.


Si il est exception-safe (comme avec les doubles), c'est OK. Mais s'il
n'est qu'exception-neutral (l'état de l'objet reste inmodifié, mais
l'exception est bien levée), alors les premiers éléments peuvent être
bien copiés, mais pas les derniers.
Au niveau mémoire il n'y a pas de problème. Côté cohérence de la donnée,
je ne suis pas persuadé que l'on peut toujours être sûr que ce n'est pas
grâve. Je ne vois pas ce qui garantit, toujours, le nétoyage de la pile
en fait.

Il y a toujours moyen de trouver une situation où la donnée (tableau) que
l'on veut modifier (par affectation) a une durée de vie qui englobe le
bloc try-catch qui va traiter l'exception.

Bref, cela dépend clairement de comment on veut l'utiliser. Dans
l'absolu, ce n'est pas systématiquement utilisable dans une solution
générique. (ce n'est bien qu'une parenthèse)


--
Luc Hermitte <hermitte at free.fr>
FAQ de <news:fr.comp.lang.c++> :
<http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/>
Dejanews : <http://groups.google.com/advanced_group_search>



Avatar
Marc Boyer
Olivier Azeau wrote:
wrote:
Olivier Azeau wrote:
(SNIP)



C'est exactement ce qui me gêne : "les apprendre plus tard".
Si j'apprends avec un radar de recul, qu'est ce qui va me motiver pour
*ensuite* apprendre sans ?


Ta note au partiel ?

Pareil pour les pointeurs : personne ne me fera écrire une classe string
à la main si qqun d'autre m'a déja montré std::string


Et avec un gros chèque ?

De quelle "maturité" parle-t-on ?
Celle où on forme des gens au C++ en leur apprenant à faire un paquet de
trucs sans pointeurs, pointeurs qu'un certain nombre d'entre eux ne
maîtriseront jamais ?


Ben, s'ils ne les maîtriseront jamais, autant montrer comment s'en passer
non ?

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.