De meme pour tout object alloue dynamiquement, je pourrai avoir une
fonction du genre :
FreeAndNilObj( void * obj)
{
if (obj != NULL)
{
delete obj;
obj = NULL;
}
}
* J'utilise generalement vector<> ou deque<>. * Si c'est un tableau, c'est delete[]. * Le test a NULL est inutile, delete se comporte correctement dans ce cas. * L'assignation de NULL a MonTableau est generalement inutile: ou je suis en train de retailler le tableau et il y a une autre assignation plus utile qui suit, ou je suis dans un destructeur. Il y a bien quelques cas ou c'est utile (je pense a des caches et a des calculs paresseux) mais c'est alors par conception.
Mais je pense qu'une template serait la bienvenue comme la suivante :
template <typename T> FreeAndNil(T [] anArray)
C'est pas du C++. Tu veux vraissemblablement ecrire FreeAndNil(T*& anArray)
{ if (anArray != NULL) { delete anArray; delete[]
anArray = NULL; } }
De meme pour tout object alloue dynamiquement, je pourrai avoir une fonction du genre : FreeAndNilObj( void * obj) { if (obj != NULL) { delete obj; Et tu perds l'appel au destructeur.
obj = NULL; } }
Ca vous semble une bonne solution ou non ?
Comme dit ci-dessus, mes utilisations de pointeurs sont telles qu'une remise systematique a NULL est inutile.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
Michael Moreno <michael.ToRemove.moreno@free.fr> writes:
Bonjour,
Pour liberer un tableau alloue dynamiquement, vous faites comment svp ?
* J'utilise generalement vector<> ou deque<>.
* Si c'est un tableau, c'est delete[].
* Le test a NULL est inutile, delete se comporte correctement dans ce
cas.
* L'assignation de NULL a MonTableau est generalement inutile: ou je
suis en train de retailler le tableau et il y a une autre assignation
plus utile qui suit, ou je suis dans un destructeur. Il y a bien
quelques cas ou c'est utile (je pense a des caches et a des calculs
paresseux) mais c'est alors par conception.
Mais je pense qu'une template serait la bienvenue comme la suivante :
template <typename T>
FreeAndNil(T [] anArray)
C'est pas du C++. Tu veux vraissemblablement ecrire
FreeAndNil(T*& anArray)
{
if (anArray != NULL)
{
delete anArray;
delete[]
anArray = NULL;
}
}
De meme pour tout object alloue dynamiquement, je pourrai avoir une
fonction du genre :
FreeAndNilObj( void * obj)
{
if (obj != NULL)
{
delete obj;
Et tu perds l'appel au destructeur.
obj = NULL;
}
}
Ca vous semble une bonne solution ou non ?
Comme dit ci-dessus, mes utilisations de pointeurs sont telles qu'une
remise systematique a NULL est inutile.
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
* J'utilise generalement vector<> ou deque<>. * Si c'est un tableau, c'est delete[]. * Le test a NULL est inutile, delete se comporte correctement dans ce cas. * L'assignation de NULL a MonTableau est generalement inutile: ou je suis en train de retailler le tableau et il y a une autre assignation plus utile qui suit, ou je suis dans un destructeur. Il y a bien quelques cas ou c'est utile (je pense a des caches et a des calculs paresseux) mais c'est alors par conception.
Mais je pense qu'une template serait la bienvenue comme la suivante :
template <typename T> FreeAndNil(T [] anArray)
C'est pas du C++. Tu veux vraissemblablement ecrire FreeAndNil(T*& anArray)
{ if (anArray != NULL) { delete anArray; delete[]
anArray = NULL; } }
De meme pour tout object alloue dynamiquement, je pourrai avoir une fonction du genre : FreeAndNilObj( void * obj) { if (obj != NULL) { delete obj; Et tu perds l'appel au destructeur.
obj = NULL; } }
Ca vous semble une bonne solution ou non ?
Comme dit ci-dessus, mes utilisations de pointeurs sont telles qu'une remise systematique a NULL est inutile.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
xavier
Michael Moreno wrote:
template <typename T> FreeAndNil(T [] anArray)
Si ton tableau est alloué dynamiquement, tu obtiens un pointeur sur le tableau. Donc la déclaration serait plutôt :
template <typename T> FreeAndNil(T * & anArray)
Tu as besoin de passer une référence à ton pointeur puisque tu souhaite changer sa valeur au dela de la portée de ta fonction.
delete anArray;
Si tu alloue un tableau via l'opérateur new [], tu dois libérer par le destructeur delete [] :
delete[] anArray;
FreeAndNilObj( void * obj)
Pourquoi n'en fait tu pas un template ? En utilisant systèmatiquement un pointeur sur void *, le destructeur ne sera pas appelé.
delete obj;
L'appel de delete sur un pointeur void est un comportement indéfini.
Merci beaucoup a vous deux pour votre aide precieuse.
Et en effet, je ne veux pas toujours utiliser la STL.
-- ---- http://michael.moreno.free.fr/
Ivan Vecerina
"xavier" wrote in message news:41caa53b$0$20290$ ...
Donc :
template <typename T> FreeAndNilObj(T * & obj) { if(obj) { delete obj; obj = 0; } } La norme C++ spécifie très clairement que:
delete 0; est une opération valide et sans aucun effet.
Le test if(obj) est donc inutile et redondant: template <typename T> FreeAndNilObj(T * & obj) { delete obj; obj = 0; }
Ceci dit, en C++, à cause des exceptions en particulier, il est déraisonnable d'utiliser (encore) ce genre de fonctions, et pratiquement illusoire de penser qu'elles puissent être utilisées correctement.
Ca vous semble une bonne solution ou non ?
Personnellement, j'utiliserais en priorité les conteneurs de la STL pour tout utilisation de tableau dynamique. Et un "smart pointer" comme std::auto_ptr ou (boost/tr1)::shared_ptr
pour quasi toute utilisation d'un objet alloué dynamiquement.
Ensuite, pour ce destructeur, je ferais :
template <bool is_an_array, typename T> bool FreeAndNil(T * & a) { Fort dangereux, vu la possibilité de passer une valeur
incorrecte à is_an_array lors d'une invocation.
int main() { int * a, * b;
a = new int[100]; b = new int;
cout << "a == " << (void*)a << endl; cout << "b == " << (void*)b << endl; assert (a != 0 && b != 0); assert (FreeAndNil<true>(a)); assert (FreeAndNil<false>(b)); assert (a == 0 && b == 0); Problèmes:
1) en mode release, compilé avec NDEBUG (ce qui désactive 'assert'), on se retrouve avec une fuite de mémoire... 2) en cas de lancement d'une exception, une fuite de mémoire surviendra également.
En comparaison: { std::vector<int> a(100); std::auto_ptr<int> b = new b; cout << "a == " << (void*)&a.front() << endl; cout << "b == " << (void*)b.get() << endl; } Concis et sûr.
Franchir le pas pour utiliser la librairie standard demande un effort, surtout si l'on a commencé avec du C ou un autre language. Mais ça en vaut la peine...
Bon Noël, Ivan -- http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
"xavier" <xtrochu@yahoo.com> wrote in message
news:41caa53b$0$20290$636a15ce@news.free.fr...
...
Donc :
template <typename T>
FreeAndNilObj(T * & obj) {
if(obj) {
delete obj;
obj = 0;
}
}
La norme C++ spécifie très clairement que:
delete 0;
est une opération valide et sans aucun effet.
Le test if(obj) est donc inutile et redondant:
template <typename T>
FreeAndNilObj(T * & obj)
{
delete obj;
obj = 0;
}
Ceci dit, en C++, à cause des exceptions en particulier,
il est déraisonnable d'utiliser (encore) ce genre de
fonctions, et pratiquement illusoire de penser qu'elles
puissent être utilisées correctement.
Ca vous semble une bonne solution ou non ?
Personnellement, j'utiliserais en priorité les conteneurs de la STL pour
tout utilisation de tableau dynamique.
Et un "smart pointer" comme std::auto_ptr ou (boost/tr1)::shared_ptr
pour quasi toute utilisation d'un objet alloué dynamiquement.
Ensuite, pour ce destructeur, je ferais :
template <bool is_an_array, typename T>
bool FreeAndNil(T * & a) {
Fort dangereux, vu la possibilité de passer une valeur
incorrecte à is_an_array lors d'une invocation.
int main() {
int * a, * b;
a = new int[100];
b = new int;
cout << "a == " << (void*)a << endl;
cout << "b == " << (void*)b << endl;
assert (a != 0 && b != 0);
assert (FreeAndNil<true>(a));
assert (FreeAndNil<false>(b));
assert (a == 0 && b == 0);
Problèmes:
1) en mode release, compilé avec NDEBUG (ce qui
désactive 'assert'), on se retrouve avec une
fuite de mémoire...
2) en cas de lancement d'une exception, une
fuite de mémoire surviendra également.
En comparaison:
{
std::vector<int> a(100);
std::auto_ptr<int> b = new b;
cout << "a == " << (void*)&a.front() << endl;
cout << "b == " << (void*)b.get() << endl;
}
Concis et sûr.
Franchir le pas pour utiliser la librairie standard
demande un effort, surtout si l'on a commencé avec
du C ou un autre language. Mais ça en vaut la peine...
Bon Noël,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
"xavier" wrote in message news:41caa53b$0$20290$ ...
Donc :
template <typename T> FreeAndNilObj(T * & obj) { if(obj) { delete obj; obj = 0; } } La norme C++ spécifie très clairement que:
delete 0; est une opération valide et sans aucun effet.
Le test if(obj) est donc inutile et redondant: template <typename T> FreeAndNilObj(T * & obj) { delete obj; obj = 0; }
Ceci dit, en C++, à cause des exceptions en particulier, il est déraisonnable d'utiliser (encore) ce genre de fonctions, et pratiquement illusoire de penser qu'elles puissent être utilisées correctement.
Ca vous semble une bonne solution ou non ?
Personnellement, j'utiliserais en priorité les conteneurs de la STL pour tout utilisation de tableau dynamique. Et un "smart pointer" comme std::auto_ptr ou (boost/tr1)::shared_ptr
pour quasi toute utilisation d'un objet alloué dynamiquement.
Ensuite, pour ce destructeur, je ferais :
template <bool is_an_array, typename T> bool FreeAndNil(T * & a) { Fort dangereux, vu la possibilité de passer une valeur
incorrecte à is_an_array lors d'une invocation.
int main() { int * a, * b;
a = new int[100]; b = new int;
cout << "a == " << (void*)a << endl; cout << "b == " << (void*)b << endl; assert (a != 0 && b != 0); assert (FreeAndNil<true>(a)); assert (FreeAndNil<false>(b)); assert (a == 0 && b == 0); Problèmes:
1) en mode release, compilé avec NDEBUG (ce qui désactive 'assert'), on se retrouve avec une fuite de mémoire... 2) en cas de lancement d'une exception, une fuite de mémoire surviendra également.
En comparaison: { std::vector<int> a(100); std::auto_ptr<int> b = new b; cout << "a == " << (void*)&a.front() << endl; cout << "b == " << (void*)b.get() << endl; } Concis et sûr.
Franchir le pas pour utiliser la librairie standard demande un effort, surtout si l'on a commencé avec du C ou un autre language. Mais ça en vaut la peine...
Bon Noël, Ivan -- http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
xavier
Ivan Vecerina a dis le 23/12/2004 14:03:
Le test if(obj) est donc inutile et redondant:
Oui et non.
La valeur de retour de ma fonction change suivant le cas, le test n'est donc pas inutile.
Fort dangereux, vu la possibilité de passer une valeur incorrecte à is_an_array lors d'une invocation.
En partant du principe qu'on souhaite utiliser deux fonctions différentes pour faire cette opération, je trouve qu'il est plus rapide de se tromper de nom de fonction (et donc d'appeller le mauvais operateur) que de se tromper entre <true> et <false>. L'absence de valeur par défaut oblige l'utilisateur de la fonction a choisir l'un ou l'autre et à se poser la question de celui qui est nécéssaire.
Problèmes: 1) en mode release, compilé avec NDEBUG (ce qui désactive 'assert'), on se retrouve avec une fuite de mémoire...
#if TEST && !defined(NDEBUG)
Si tu préfères, mais en l'occurence, je désactive rarement le mode déboggage dans les tests. Ceci étant dit, tu as tout à fait raison de remarquer que ce n'est pas une bonne habitude de faire cela dans un assert.
Ivan Vecerina a dis le 23/12/2004 14:03:
Le test if(obj) est donc inutile et redondant:
Oui et non.
La valeur de retour de ma fonction change suivant le cas, le test n'est
donc pas inutile.
Fort dangereux, vu la possibilité de passer une valeur
incorrecte à is_an_array lors d'une invocation.
En partant du principe qu'on souhaite utiliser deux fonctions
différentes pour faire cette opération, je trouve qu'il est plus rapide
de se tromper de nom de fonction (et donc d'appeller le mauvais
operateur) que de se tromper entre <true> et <false>. L'absence de
valeur par défaut oblige l'utilisateur de la fonction a choisir l'un ou
l'autre et à se poser la question de celui qui est nécéssaire.
Problèmes:
1) en mode release, compilé avec NDEBUG (ce qui
désactive 'assert'), on se retrouve avec une
fuite de mémoire...
#if TEST && !defined(NDEBUG)
Si tu préfères, mais en l'occurence, je désactive rarement le mode
déboggage dans les tests. Ceci étant dit, tu as tout à fait raison de
remarquer que ce n'est pas une bonne habitude de faire cela dans un assert.
La valeur de retour de ma fonction change suivant le cas, le test n'est donc pas inutile.
Fort dangereux, vu la possibilité de passer une valeur incorrecte à is_an_array lors d'une invocation.
En partant du principe qu'on souhaite utiliser deux fonctions différentes pour faire cette opération, je trouve qu'il est plus rapide de se tromper de nom de fonction (et donc d'appeller le mauvais operateur) que de se tromper entre <true> et <false>. L'absence de valeur par défaut oblige l'utilisateur de la fonction a choisir l'un ou l'autre et à se poser la question de celui qui est nécéssaire.
Problèmes: 1) en mode release, compilé avec NDEBUG (ce qui désactive 'assert'), on se retrouve avec une fuite de mémoire...
#if TEST && !defined(NDEBUG)
Si tu préfères, mais en l'occurence, je désactive rarement le mode déboggage dans les tests. Ceci étant dit, tu as tout à fait raison de remarquer que ce n'est pas une bonne habitude de faire cela dans un assert.