OVH Cloud OVH Cloud

[BCB6 /STL] Violation d'acces dans un classe et sa collection

39 réponses
Avatar
Olivier
Bonjoiur
je fait une collection d'article (std::vector<TArticle *> _pCoArt;)

le probleme quand je supprime un article
ou quand il est le dernier et que je veuille en ajouter un
autre j'ai une violation d'acces

voici le code de la suppression :


bool __fastcall TCoArticles::DeleteArticle(TArticle& Art)
{//@CODE_347

bool bRes=false;

if(int max =Count()>0){

int i=0;

if(SearchArticle(Art,i)){

TArticle *_pArt=_pCoArt.at(i);

if(i==max || max==1){
_pCoArt.push_back();
}else{
_pCoArt.erase(&_pArt);
}
delete _pArt;
bRes=true;
}
}else{
TMyError Err(7,"Collection d'article est vide");
throw Err;
}
return bRes;
}//@CODE_347


le code SearchArticle

bool __fastcall TCoArticles::SearchArticle(TArticle& Art, int& i)
{//@CODE_357
bool bRes=false;
std::vector<TArticle*>::iterator i_end =_pCoArt.end();
int j=0;

for(std::vector<TArticle*>::iterator it=_pCoArt.begin();it!=i_end;++it){

if((*it)->NomArt==Art.NomArt && (*it)->Description==Art.Description &&
(*it)->Categorie==Art.Categorie && (*it)->Prix==Art.Prix){

i=j;
bRes=true;
break;

}
j++;
}

return bRes;
}//@CODE_357

ou est mon erreur ?
que dois je faire ?

merci de vos reponses....
--
Cordialement ,
Sarda Olivier

Site Web:
http://membres.lycos.fr/osarda

10 réponses

1 2 3 4
Avatar
kanze
"Olivier" wrote in message
news:<3f24ea3a$0$24784$...

je fait une collection d'article (std::vector<TArticle *> _pCoArt;)

le probleme quand je supprime un article ou quand il est le dernier et
que je veuille en ajouter un autre j'ai une violation d'acces

voici le code de la suppression :


Il y a plusieurs problèmes...

bool __fastcall TCoArticles::DeleteArticle(TArticle& Art)
{//@CODE_347

bool bResúlse;

if(int max =Count()>0){

int i=0;

if(SearchArticle(Art,i)){

TArticle *_pArt=_pCoArt.at(i);

if(i==max || max==1){
_pCoArt.push_back();


C'est quoi, ce push_back. Un push_back sans paramètre ne doit même pas
passer le compilateur.

C'est quoi aussi, la valeur de max ? Est-ce le nombre d'éléments, ou
est-ce l'indice du dernier élément ? (Dans le premier cas, tu n'aurais
jamais i == max avec ta fonction SearchArticle.)

}else{
_pCoArt.erase(&_pArt);


Il n'y a pas de fonction erase qui prend l'adresse d'une variable
locale. Avec certaines implémentations (dont g++, la version debug de
StlPort, et la version debug des Dinkumware récents), cette ligne ne se
compilera même pas -- erase veut un iterator, non un pointeur. (Dans
certaines implémentations, un itérateur d'un vector est un pointeur,
mais la norme ne l'exige pas, et à mon avis, ce n'est pas un bon choix
dans l'implémentation.)

Alors, des deux chose une :
- ou bien, std::vector<>::iterator n'est pas un pointeur, et tu as une
erreur de compile,
- ou bien, std::vector<>::iterator est un pointeur, mais tu passes un
pointeur qui ne pointe pas dans le vector, et tu as donc un
comportement indéfini.

Personnellement, je modifierais SearchArticle pour qu'elle renvoie un
iterateur -- pCoArt.end(), si l'élément n'était pas trouver, et
j'écrirais quelque chose du genre :

typedef std::vector< TArticle* > Vect ;
Vect::const_iterator pos = SearchArticle( art ) ;
bool found = pos != _pCoArt.end() ;
if ( found ) {
delete *pos ;
_pCoArt.erase( _pCoArt.begin() + (pos - _pCoArt.end()) ) ;
}
return found ;

(Si l'expression du paramètre d'erase semble compliquer, c'est que je
suppose que SearchArticle est en fait une fonction const, et qu'il
renvoie un itérateur const, or que erase veut un itérateur non const.)

Formellement, faire le delete avant l'erase est interdit. Pratiquement,
il n'y a pas de risque.

}
delete _pArt;
bRes=true;
}
}else{
TMyError Err(7,"Collection d'article est vide");
throw Err;
}
return bRes;
}//@CODE_347


Ta convention de nommage déroute, pour dire le moindre. Pourquoi pas
simplement Article et ArticleList pour les noms des types, par exemple ?

le code SearchArticle

bool __fastcall TCoArticles::SearchArticle(TArticle& Art, int& i)
{//@CODE_357
bool bResúlse;
std::vector<TArticle*>::iterator i_end =_pCoArt.end();
int j=0;

for(std::vector<TArticle*>::iterator it=_pCoArt.begin();it!=i_end;++it){

if((*it)->NomArt==Art.NomArt && (*it)->Description==Art.Description &&
(*it)->Categorie==Art.Categorie && (*it)->Prix==Art.Prix){

i=j;
bRes=true;
break;

}
j++;
}

return bRes;
}//@CODE_357


Est-ce que tu connais la fonction standard find_if ? Ou simplement
j'ai l'impression que tu pourrais très bien définir un
operator== sur TArticle :

bool
operator==( TArticle const& lhs, TArticle const& rhs )
{
return lhs.NomArt == rhs.NomArt
&& lhs.Description == rhs.Description
&& lhs.Categorie == rhs.Categorie
&& lhs.Prix == rhs.Prix ;
}

(Sauf que je me démande si c'est logique que l'identité d'un article
comprend le prix. C'est même probable qu'une simple comparaison des noms
correspond davantage à la sémantique voulue.)

Avec ça, puisque tu travailles avec des pointeurs, il faut une classe
d'indirection dans la comparaison :

template< typename T >
struct IsEqualPointedTo
{
bool operator()( T const* lhs, T const* rhs ) const
{
return *lhs == *rhs ;
}
} ;


std::vector< TArticle* >::const_iterator
TCoArticles::SearchArticle( TArticle const& article ) const
{
return find_if( _pCoArt.begin(), _pCoArt.end(),
std::bind2nd( IsEqualPointedTo< TArticle >(),
&article ) ) ;
}

(Je crois que c'est bon, mais je ne l'ai pas essayé.)

Une autre possiblité, peut-être plus idiomatique pour C++, serait de
définir une classe embriquée à la place de la fonction SearchArticle.
Classe qui compare l'article donné par un pointeur à un article qu'il
contient. Et puis, laisser le soin de l'utilisateur d'écrire le find_if.

ou est mon erreur ?


Ton erreur, au moins celle qui provoque la faute de protection, c'est
d'utiliser l'adresse d'une variable locale comme si c'était un
itérateur. Mais il y a beaucoup de chose à dire sur le code

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
kanze
Fabien LE LEZ wrote in message
news:...
On Mon, 28 Jul 2003 15:10:09 +0200, Luc Hermitte
wrote:

Hum ... pas d'accord. Si la classe est complexe, avec plein de
champs, sans constructeur sans arguments, opérateurs de recopie et
autres moyens de vérifier que l'objet manipulé est bien valide ... je
fais comme lui.


Etant donné que l'op parlait d'une collection d'articles et pas de
pointeurs, et étant donné son niveau présumé (d'après son post),
j'estime que la question "Es-tu bien sûr que c'est ce que tu veux ?"
est légitime.


Probablement. Parmi pas mal d'autres questions.

Surtout, je crois qu'il lui faut un bon bouquin : l'absence de const
tire déjà un signal d'alarme chez moi, de même que les conventions de
nommage. (Il pourrait commencer par les trois Scott Meyers, je crois.
Ils semblent correspondre à ce qu'il lui faut.) À un niveau plus élevé,
les critères de comparaison des articles me fait poser des questions sur
ces connaissances en conception. Il lui faudrait alors aussi un bon
bouquin sur la conception OO (et d'autre) en plus d'un bouquin sur le
C++ ; pour commencer, la réponse à ta question dépend probablement du
rôle que joue Article dans l'application. Si c'est une valeur, c'est
probable qu'un vector d'objets serait préférable à un vector de
pointeurs. Si c'est une entité, en revanche, le vector de pointeurs
convient parfaitement, mais la comparaison se ferait probablement sur
l'adresse, et non sur les valeurs. Sauf que typiquement, dans ce cas-là,
sa fonction prendra non une Article, mais une valeur qui sert comme clé
pour trouver l'article. Et on n'est pas loin d'un map. (Ce qui est une
autre question -- puisqu'il cherche un élément dans la collection,
peut-être std::set ou std::map conviendra mieux que std::vector.)

En revanche, je le trouve un peu curieux que personne n'a signalé
l'erreur fatale qu'il a fait -- le fait d'utiliser l'adresse d'une
variable locale comme itérateur dans un vector. Avec une bonne
implémentation moderne, le code n'aurait même pas compilé, mais avec une
implémentation plus ancienne ou moins bonne, le core dump ne m'étonne
pas. Une implémentation typique ferait probablement quelque chose du
genre :

copy( userIter + 1, end(), userIter ) ;

pour commencer -- si les itérateurs sont des pointeurs, et userIter
pointe en fait dans la pile, copy va itérer beaucoup avant d'arriver à
end() (qui lui n'est certainement pas dans la pile). Sur une machine où
la pile croît vers le bas (Intel, Sparc, etc.), il va commencer par
cramer toute la pile, ce qui est déjà un bon début -- quoiqu'il arrive
par la suite, le core va être drôlement difficile à exploiter.

Je n'avais jamais considéré ce genre d'erreur, mais à mon avis, c'est
encore un bon argument pour l'utilisation des classes comme itérateurs,
et non des pointeurs.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
kanze
Fabien LE LEZ wrote in message
news:...
On Mon, 28 Jul 2003 15:10:09 +0200, Luc Hermitte
wrote:

Hum ... pas d'accord. Si la classe est complexe, avec plein de
champs, sans constructeur sans arguments, opérateurs de recopie et
autres moyens de vérifier que l'objet manipulé est bien valide ... je
fais comme lui.


Etant donné que l'op parlait d'une collection d'articles et pas de
pointeurs, et étant donné son niveau présumé (d'après son post),
j'estime que la question "Es-tu bien sûr que c'est ce que tu veux ?"
est légitime.

Personnellement, j'utilise plus souvent des collections de pointeurs
que des collections de classes.


Qu'entends-tu par "utiliser plus souvent" ? Généralement, dans mes
programmes, j'ai très peu de collections de pointeurs (et la plupart
du temps il s'agit de pointeurs qui se "deletent" eux-mêmes) et
beaucoup de collections d'objets, mais comme les quelques collections
de pointeurs ont un rôle fondamentale (par exemple, l'ensemble des
fenêtres et sous-fenêtres de mon application est une collection de
pointeurs en forme d'arbre, et la quasi-totalité du code est dans ses
fonctions membres), on pourrait aussi dire que "j'utilise plus souvent
des collections de pointeurs" ;-)


Et si j'ai un std::map< std::string, Class* >, est-ce une collection des
valeurs, ou une collection de pointeurs ? (C'est probablement la
collection que j'utilise la plus dans mon code.)

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
Luc Hermitte
wrote in news:d6652001.0307300126.10a8b431
@posting.google.com:
En revanche, je le trouve un peu curieux que personne n'a signalé
l'erreur fatale qu'il a fait -- le fait d'utiliser l'adresse d'une
variable locale comme itérateur dans un vector.


Je l'avais déjà fait sur nzn.fr.c++ :)

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

Avatar
Fabien LE LEZ
On 30 Jul 2003 02:30:18 -0700, wrote:

Et si j'ai un std::map< std::string, Class* >, est-ce une collection des
valeurs, ou une collection de pointeurs ?


Je dirais une collection de pointeurs, étant donné qu'on doit gérer
les pointeurs (et la création des objets pointés) soi-même.


--
Tout sur fr.* (FAQ, etc.) : http://www.usenet-fr.net/fur/
et http://www.aminautes.org/forums/serveurs/tablefr.html
Archives : http://groups.google.com/advanced_group_search
http://www.usenet-fr.net/fur/usenet/repondre-sur-usenet.html

Avatar
Gabriel Dos Reis
writes:

| Je n'avais jamais considéré ce genre d'erreur, mais à mon avis, c'est
| encore un bon argument pour l'utilisation des classes comme itérateurs,
| et non des pointeurs.

Quelqu'un vient juste de proposer sur la liste de libstdc++-v3 qu'on
en revienne aux pointeurs bruts.

-- Gaby
Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
writes:

| Je n'avais jamais considéré ce genre d'erreur, mais à mon avis,
| c'est encore un bon argument pour l'utilisation des classes comme
| itérateurs, et non des pointeurs.

Quelqu'un vient juste de proposer sur la liste de libstdc++-v3 qu'on
en revienne aux pointeurs bruts.


Est-ce qu'ils ont pu donner des raisons ?

En fait, on pourrait arguer effectivement qu'il faut une option pour
pouvoir le faire. Parce qu'il y a sûrement du code existant qui y
compte -- le code est, nous le savons, incorrect, mais il marchait
avant.

En revanche, j'aimerais bien savoir comment ils comptent faire une
version debug de la bibliothèque avec des pointeurs à la place des
itérateurs. Et tôt ou tard, je crois qu'il va falloir une version debug
à g++ aussi.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
Luc Hermitte
"Olivier" wrote in
news:3f290258$0$11008$:

je m'explique je voulais recherche "a la main" les object presents
dans la collection par le biais d'une boucle

la logique de suppresion en "pseudo" est

debut
entiet i=0
si objet[i] trouve alors file://searcharticle
si on est sur le prmier de la collection ou le dernier de la
collection alors
file://pop_back
sinon
supprimer l'article[i]
fin si
fin si
fin


Tu t'embêtes vraiment, l'algo canon est de rechercher l'itérateur
correspondant à l'article à supprimer et appliquer erase() ensuite.


Cepandant cette methode fait partie d'une classe
si je fais une surchage d'operateur tout mes autre operateur = dans
les autre fonction vont etre surcharge non ?
comment faire pour que ce soit fait a un fonction


o_O ? Non.

Si tu surcharges operator==() pour les const Articles, tu n'auras fourni
qu'une seule nouvelle fonction de comparaison qui ne sera utilisée que
pour les Article, et rien d'autre.


Pour effacer le dernier article j'ai essaye avec pop_front()
BCB 6 me reponds


Pourquoi t'embêtes-tu ? Utilise erase(). James et moi-même (sur nzn)
t'avons fourni du code plus simple dans la logique C++. Profites-en.

Message-ID: <news:


d'autre par sur le destrcuteur de ma classe collection
je detruit tout les objets.J' ai code par rapport a ma logique (je
viens de vb beurk!!!)
est plus performant de faire une surcharge d'operateur ?


Quel rapport ?
Je ne vois pas de quoi tu parles.

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

Avatar
Fabien LE LEZ
Prière de lire d'urgence la page
<http://www.giromini.org/usenet-fr/repondre.html>


--
Tout sur fr.* (FAQ, etc.) : http://www.usenet-fr.net/fur/
et http://www.aminautes.org/forums/serveurs/tablefr.html
Archives : http://groups.google.com/advanced_group_search
http://www.usenet-fr.net/fur/usenet/repondre-sur-usenet.html
Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
writes:

| Gabriel Dos Reis wrote in message
| news:...
| > writes:

| > | Je n'avais jamais considéré ce genre d'erreur, mais à mon avis,
| > | c'est encore un bon argument pour l'utilisation des classes
| > | comme itérateurs, et non des pointeurs.

| > Quelqu'un vient juste de proposer sur la liste de libstdc++-v3
| > qu'on en revienne aux pointeurs bruts.

| Est-ce qu'ils ont pu donner des raisons ?


En somme, des histoires d'optimisation, mais...

Oui : comme le compilateur (sur sa machine) est assez idiot pour ne
pas mettre une structure qui contient uniquement un pointeur dans un
registre, il préfère que nous renoncions à un type distinct de T*.


C'est bête, mais j'avais oublié cette histoire-là. Si ça te rassure, g++
n'est pas le seul à être aussi idiot, loin de là. (Ce qui est curieux,
parce qu'il me semble d'avoir lu des propos de Strustrup sur l'intérêt
de passer des petites classes par des régistres il y a environ 12/13
ans, sinon plus. Je me démande s'il n'en a pas parlé dans la première
version de TC++PL. Ce n'est donc pas vraiment une idée nouvelle.)

Le problème est que, si nous faisions ça, il nous faudrait logiquement
virer les objets fonctionnels car souffrant des mêmes idioties de la
part du compilateur.


Si on en arrive là, il faudrait carrément virer le C++, parce qu'on veut
que le programmeur fasse le boulot, et non le compilateur. Mais alors,
virons aussi le C, tant qu'on y est.

Comme souvent, le problème est ailleurs et la solution effective est
d'enseigner au compilateur à inliner effectivement et virer les
junks. Car les opérations incriminées sont essentiellement

1) lire la valeur brute du pointeur
2) comparer les valeurs brutes de deux pointeurs.


J'aurais pensé que le passage des paramètres et le retour des fonctions
soient où la différence se fait le plus sentir. Si j'ai quelque chose
comme :

struct S { T* ptr } s1, s2 ;

s1.ptr == s2.ptr ;

avec tout visible au compilateur (grace aux fonctions inline), je me
poserais vraiment des questions si le compilateur générait un code
différent de ce qu'il aurait fait avec des pointeurs bruts.

Le problème des paramètres et des retours de fonctions est un peu plus
subtile, parce qu'il vaut mieux que le compilateur fasse la même chose
au point de l'appel et dans la fonction (qui sont souvent dans deux
unités de compilations différentes, compilées avec des options
d'optimisation différentes). Passer une classe comme S, ci-dessus,
pourrait poser des problèmes si on avait besoin ou d'un côté ou de
l'autre. Et pour appeler une fonction membre, il en faut l'adresse.

Actuellement, dès que le compilateur voir "struct" il dit "Oh là,
celui là ne veut pas d'efficacité, allez hop dans le tas" sans
chercher à savoir si le "struct" en question sert just à distinguer
une valeur des autres et que cette distinction est purement
compile-time.

On voit que le compilateur est écrit essentiellement par des
programmeurs C.


Juste curieux, mais par « est écrit », est-ce que tu veux dire « a été
écrit », ou « s'écrit actuellement » ? (Le français est un peu ambigu à
cet égard. Ici, il vaut mieux l'allemand, qui a deux passifs : « ist
geschrieben », pour exprimé l'état, et « wird gescrieben »,
littéralement « devient écrit », pour l'action en cour.)

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

1 2 3 4