Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

problème sur un delete

6 réponses
Avatar
cyan
bonjour,

j'ai une erreur qui se produit sur un delete et je ne comprends pas.

ma m=E9thode prends en param=E8tre une adresse email, celle-ci doit se
charger de l'=E9liminer d'une liste d'adresse email( celle-ci est un
membre de ma classe).
Seul dans le cas o=F9 l'adresse =E0 supprimer est en t=EAte de liste, la
m=E9thode ne plante pas.

merci d'avance pour votre aide.

yann

voici ma m=E9thode


STDMETHODIMP COutlookEvents::modifyAddressees(CHAR* email_account)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

// TODO : ajoutez ici votre code d'impl=E9mentation
char * found =3D NULL;
char * next_email =3D NULL;
char * tmp =3D NULL;

std::cerr<<"modifyAddressees"<<std::endl;

if( email_account )
{
/// recherche email_account dans destinataire
found =3D strstr(destinataire, email_account);

if( found )
{
std::cerr<<"trouv=E9"<<std::endl;
next_email =3D strchr(found, ';');

std::cerr<<destinataire<<std::endl;

/// email_account est en t=EAte de liste ?
if( found =3D=3D destinataire )
{
std::cerr<<"trouv=E9 2 "<<std::endl;

if( next_email )
{
std::cerr<<"en tete de liste"<<std::endl;
next_email++;
*(next_email-1) =3D '\0';

std::cerr<<"avt new"<<std::endl;
destinataire =3D new char[strlen(next_email)+1];

std::cerr<<"apres new avt strcpy"<<std::endl;
strcpy(destinataire, next_email);

std::cerr<<"apres strcpy"<<std::endl;

}
else
delete destinataire;

}
else
{
/// y a-t-il d'autres adresses emails apr=E8s celle =E0 supprimer ?
if( next_email )
{
std::cerr<<"au milieur de la liste"<<std::endl;

tmp =3D destinataire;

/// s=E9paration entre l'adresse email =E0 supprimer et les autres
emails =E0 garder( qui sont avant )
*(found-1) =3D '\0';

///positionnement sur le 1er caractere de l'adresse mail
next_email++;

/// s=E9paration entre l'adresse email =E0 supprimer et les autres
emails =E0 garder( qui sont apr=E8s )
*(next_email-1) =3D '\0';

destinataire =3D new char[strlen(tmp)+strlen(next_email)+3];

strcpy(destinataire, tmp);

/// raccrochage
strcat(destinataire,";");
strcat(destinataire, next_email);

}
else /// email_account est en fin de liste
{
std::cerr<<"en fin de liste"<<std::endl;
*(found-1) =3D '\0';


}

}/// end if( found =3D=3D destinataire )


}/// end if( found )
std::cerr<<destinataire<<std::endl;

if( found )
std::cerr<<"found : "<< found <<std::endl;

if( tmp )
std::cerr<<"tmp : "<< tmp <<std::endl;

if( next_email )
std::cerr<<"next : "<< next_email <<std::endl;

std::cerr<<"avant delete"<<std::endl;
delete found; ////PLANTAGE
std::cerr<<"apres delete"<<std::endl;
}
return S_OK;
}

6 réponses

Avatar
Fabien LE LEZ
On 10 Aug 2005 04:43:07 -0700, "cyan" :

j'ai une erreur qui se produit sur un delete et je ne comprends pas.


Franchement, ton code me paraît trop compliqué pour avoir une chance
de fonctionner.
Et comme je n'ai aucune idée de l'endroit où se trouve le new qui va
avec le delete, je ne risque pas de pouvoir t'aider.

Note par ailleurs que "delete" et "new[]" sont incompatibles --
delete[] va avec new[] et delete avec new.
Ou plutôt, "delete" correspond à "new" et... c'est tout. AMHA, il se
passera un sacré bout de temps avant que tu aies un usage légitime de
new[].

Tu essaies apparemment d'utiliser des chaînes de caractères, mais en
C, avec des char*. Dans le meilleur des cas, c'est pénible à écrire
correctement, pénible à lire, pénible à maintenir. (Pour le pire des
cas, remplacer "pénible" par "impossible".)

En C++, une chaîne de caractère, c'est un std::string. Pas de malloc,
de new[] ou de delete[], pas de problème pour gérer la taille, ni de
difficultés à copier.

D'autre part, j'ai l'impression que tu utilises une chaîne pour
stocker une liste de chaînes séparées par un espace.
Ce serait beaucoup plus simple de faire carrément un tableau de
chaînes :

STDMETHODIMP COutlookEvents::modifyAddressees(CHAR* email_account)


Dans quelles limites peux-tu modifier ce prototype ?

L'idéal serait :

STDMETHODIMP COutlookEvents::modifyAddressees
(std::string const& email_account)

Si ce n'est pas possible, une solution parfaitement acceptable :

STDMETHODIMP COutlookEvents::modifyAddressees
(char const* email_account)

Si vraiment tu ne peux rien changer, au moins assure-toi que le
paramètre ne sera pas modifié :

STDMETHODIMP COutlookEvents::modifyAddressees
(CHAR* PARAM_email_account)
{
std::string email_account (PARAM_email_account);
// suite de la fonction...
}

Avatar
Arnaud Meurgues
cyan wrote:

j'ai une erreur qui se produit sur un delete et je ne comprends pas.


Je pense que vous allez mieux comprendre si je vous pose la question
suivante :
Quelle est la taille du bloc mémoire que vous voulez libérer ?

found pointe au milieu d'un bloc mémoire. Il ne correspond donc pas à
l'adresse d'un bloc alloué. Vous ne pouvez pas choisir de désallouer une
partie d'un bloc mémoire. De plus, même si c'était possible, il n'y a
aucun moyen de savoir quelle taille de bloc vous voulez désallouer (la
désallocation ne s'occupe pas du contenu de ce qui est désallouer, et le
fait qu'il y a un '' ne l'intéresse en rien).

Donc, on ne peut désallouer un bloc qu'avec l'adresse qui a été
retrournée lors de son allocation, et c'est tout le bloc qui est
désalloué. C'est pourquoi le delete ne plante pas lorsque l'adresse est
en tête de liste : found est alors l'adresse de début du bloc.

Bref, ce qu'il faut faire, alors, c'est allouer un bloc de la bonne
taille, y recopier ce que vous souhaitez garder, puis deleter l'ancien
bloc (avec l'adresse de début de bloc, c'est-à-dire destinataire).

Un manière simple de faire serait d'itérer sur toutes les adresses de
destinataire et de ne recopier dans le résultat que les adresses
différentes de celle à supprimer. C'est un peu moins efficace (o(n) au
lieu de o(n/2)), mais probablement beaucoup plus clair à lire, et ça
couvre le cas où la même adresse serait présente deux fois.


--
Arnaud

Avatar
Fabien LE LEZ
On 10 Aug 2005 04:43:07 -0700, "cyan" :

ma méthode prends en paramètre une adresse email, celle-ci doit se
charger de l'éliminer d'une liste d'adresse email( celle-ci est un
membre de ma classe).


Voici comment j'écrirais une telle classe :

class Bidule
{
public:
void SupprimerAdresse (std::string const& adresse_a_supprimer);

private:
typedef std::vector<std::string> ListeAdresses;
ListeAdresses liste_adresses;
};

void Bidule::SupprimerAdresse (std::string const& adresse_a_supprimer)
{
ListeAdresses::iterator it_adresse_a_supprimer std::find (liste_adresses.begin(), liste_adresses.end(),
adresse_a_supprimer);

if (it_adresse_a_supprimer == liste_adresses.end())
{
// On vire l'adresse du tableau
liste_adresses.erase (it_adresse_a_supprimer);
}
else
{
// L'adresse n'était pas dans le tableau
}
}

Note : ça paraît un peu long, mais c'est juste parce que j'ai tendance
à employer des identifiants à rallonge. Ce qui n'est pas forcément un
mal, d'ailleurs.

Avatar
Arnaud Meurgues
Fabien LE LEZ wrote:

void Bidule::SupprimerAdresse (std::string const& adresse_a_supprimer)
{
ListeAdresses::iterator it_adresse_a_supprimer > std::find (liste_adresses.begin(), liste_adresses.end(),
adresse_a_supprimer);

if (it_adresse_a_supprimer == liste_adresses.end())


C'est pas !=, plutôt ?

{
// On vire l'adresse du tableau
liste_adresses.erase (it_adresse_a_supprimer);
}
else
{
// L'adresse n'était pas dans le tableau
}
}


Par ailleurs, effectivement, pour deleter un tableau de char, c'est
delete[] qu'il faut utiliser. Mais attention, si ce tableau a été alloué
par malloc, alors il faut utiliser free et non delete[].

--
Arnaud

Avatar
Fabien LE LEZ
On Wed, 10 Aug 2005 14:47:51 +0200, Arnaud Meurgues
:

if (it_adresse_a_supprimer == liste_adresses.end())


C'est pas !=, plutôt ?


Effectivement. C'était pour voir si tu suivais.


Avatar
cyan
merci pour vos remarques et réponses, j'utiliserai dorénavant le type
string