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

auto_ptr et vérification que le pointeur est bien alloué ?

12 réponses
Avatar
Stephane Wirtel
bonjour,

Est-il possible de vérifier qu'un pointeur intélligent est bien alloué ou pas ?
style :

auto_ptr <TypeVariable> ptr (new TypeVariable ("Toto"));
if (ptr) {
}

Je pose la question, car je l'avais mis dans un 'try' 'catch' en espérant que si l'allocation
se déroulerait mal, celui-ci lancerait une exception, mais rien de tel ne se produit.

Merci,

Stéphane

10 réponses

1 2
Avatar
Ahmed MOHAMED ALI
Bonjour,

Est-il possible de vérifier qu'un pointeur intélligent est bien alloué ou
pas ?

style :

auto_ptr <TypeVariable> ptr (new TypeVariable ("Toto"));
if (ptr) {
}

auto_ptr n'est pas alloué mais c'est un pointeur sur TypeVariable qui est

alloué.
auto_ptr prend possession de ce pointeur.Si l'opérateur new lance une
exception bad_alloc, alors l'auto_ptr n'est pas construit et tu peux
capturer cette exception dans ton code.En revanche,si l'opérateur new
retourne 0 ,là le test if est utile.
Ahmed


"Stephane Wirtel" wrote in message
news:d3fv50$jg7$
bonjour,

Est-il possible de vérifier qu'un pointeur intélligent est bien alloué ou
pas ?

style :

auto_ptr <TypeVariable> ptr (new TypeVariable ("Toto"));
if (ptr) {
}

Je pose la question, car je l'avais mis dans un 'try' 'catch' en espérant
que si l'allocation

se déroulerait mal, celui-ci lancerait une exception, mais rien de tel ne
se produit.


Merci,

Stéphane


Avatar
Stephane Wirtel
Merci de l'information,

Voici un exemple de ce que j'ai codé afin de répondre à mon problème d'auto_ptr;

Pourriez-vous me dire ce que vous en pensez ?
Attention, Il ne s'agit que d'un exemple, je viens de le coder dans mon client mail.
Donc il se peut qu'il ne compile pas ;-)

#include <iostream>
#include <memory>
#include <exception>

using namespace std;

enum TypeImportFile {
TextImportFile = 0,
BinaryImportFile
};

class ImportFile {
public:
ImportFile (TypeImportFile p_Type) : m_Type (p_Type) {
}
virtual ~ImportFile () = 0;
TypeImportFile GetType (void) {
return m_Type;
}
};

class TextImportFile : public ImportFile {
public:
TextImportFile (void) : ImportFile (TextImportFile) {
}
~TextImportFile (void) {
}
};

class BinaryImportFile : public ImportFile {
public :
BinaryImportFile (void) : ImportFile (BinaryImportFile) {
}
~BinaryImportFile (void) {
}
};

class TypeImportFileNotFoundException : public exception {
public:
TypeImportFileNotFoundException (TypeImportFile p_Type) : m_Type (p_Type) {
}
const char *what () {
return "Type non trouvé";
}
private:
TypeImportFile m_Type;
};

auto_ptr <ImportFile> GetImportFile (TypeImportFile p_Type) {
switch (p_Type) {
case TextImportFile:
return auto_ptr <ImportFile> (new TextImportFile());
case BinaryImportFile:
return auto_ptr <ImportFile> (new BinaryImportFile());
default :
throw TypeImportFileNotFoundException (p_Type);

}
}

int main (int argc, char **argv) {
try {
auto_ptr <ImportFile> importFile = GetImportFile (BinaryImportFile);
importFile->SaveToDatabase ();
} catch (TypeImportFileNotFoundException& pException) {
cout << "Une exception a été levée : " << pException.what () << endl;
}
return 0;
}

Merci
Avatar
Ahmed MOHAMED ALI
int main (int argc, char **argv) {
try {
auto_ptr <ImportFile> importFile = GetImportFile (BinaryImportFile);
importFile->SaveToDatabase ();
} catch (TypeImportFileNotFoundException& pException) {
cout << "Une exception a été levée : " << pException.what () << endl;
}
return 0;



Je ne vois pas où tu gères l'exception std::bad_alloc.
Si tu compile sous VC++,le mieux c'est de tester le retour de new car à ma
connaissance il ne lance pas cette exception.
donc en modifiant légèrement ton code:
try {
auto_ptr <ImportFile> importFile = GetImportFile (BinaryImportFile);
if (importFile.get()) // l'opérateur new de VC++ renvoie 0 si
l'allocation échoue
{
importFile->SaveToDatabase ();
}
} catch(std::bad_alloc& badAlloc) //pour les compilo qui se conforment à
la norme
{
... ton traitement ...
}
} catch (TypeImportFileNotFoundException& pException) {
cout << "Une exception a été levée : " << pException.what () << endl;
}

Ahmed


"Stephane Wirtel" wrote in message
news:d3g40s$m5c$
Merci de l'information,

Voici un exemple de ce que j'ai codé afin de répondre à mon problème
d'auto_ptr;


Pourriez-vous me dire ce que vous en pensez ?
Attention, Il ne s'agit que d'un exemple, je viens de le coder dans mon
client mail.

Donc il se peut qu'il ne compile pas ;-)

#include <iostream>
#include <memory>
#include <exception>

using namespace std;

enum TypeImportFile {
TextImportFile = 0,
BinaryImportFile
};

class ImportFile {
public:
ImportFile (TypeImportFile p_Type) : m_Type (p_Type) {
}
virtual ~ImportFile () = 0;
TypeImportFile GetType (void) {
return m_Type;
}
};

class TextImportFile : public ImportFile {
public:
TextImportFile (void) : ImportFile (TextImportFile) {
}
~TextImportFile (void) {
}
};

class BinaryImportFile : public ImportFile {
public :
BinaryImportFile (void) : ImportFile (BinaryImportFile) {
}
~BinaryImportFile (void) {
}
};

class TypeImportFileNotFoundException : public exception {
public:
TypeImportFileNotFoundException (TypeImportFile p_Type) : m_Type (p_Type)
{

}
const char *what () {
return "Type non trouvé";
}
private:
TypeImportFile m_Type;
};

auto_ptr <ImportFile> GetImportFile (TypeImportFile p_Type) {
switch (p_Type) {
case TextImportFile:
return auto_ptr <ImportFile> (new TextImportFile());
case BinaryImportFile:
return auto_ptr <ImportFile> (new BinaryImportFile());
default :
throw TypeImportFileNotFoundException (p_Type);

}
}

int main (int argc, char **argv) {
try {
auto_ptr <ImportFile> importFile = GetImportFile (BinaryImportFile);
importFile->SaveToDatabase ();
} catch (TypeImportFileNotFoundException& pException) {
cout << "Une exception a été levée : " << pException.what () << endl;
}
return 0;
}

Merci


Avatar
Stephane Wirtel
int main (int argc, char **argv) {
try {
auto_ptr <ImportFile> importFile = GetImportFile (BinaryImportFile);
importFile->SaveToDatabase ();
} catch (TypeImportFileNotFoundException& pException) {
cout << "Une exception a été levée : " << pException.what () << endl;
}
return 0;




Je ne vois pas où tu gères l'exception std::bad_alloc.
Si tu compile sous VC++,le mieux c'est de tester le retour de new car à ma
connaissance il ne lance pas cette exception.
donc en modifiant légèrement ton code:
try {
auto_ptr <ImportFile> importFile = GetImportFile (BinaryImportFile);
if (importFile.get()) // l'opérateur new de VC++ renvoie 0 si
l'allocation échoue
{
importFile->SaveToDatabase ();
}
} catch(std::bad_alloc& badAlloc) //pour les compilo qui se conforment à
la norme
{
... ton traitement ...
}
} catch (TypeImportFileNotFoundException& pException) {
cout << "Une exception a été levée : " << pException.what () << endl;
}
Merci Ahmed,


Concernant le compilateur, il s'agit soit de C++ Builder ou de GCC, mais j'ai une plus grosse préférence pour GCC.

Il est vrai que dans le bout de code, je n'ai pas intégré de catch sur le bad_alloc, comme dit plus haut, il s'agit
simplement d'un exemple que j'ai pondu le temps d'écrire le mail ;-)

Ce qui me fait peur, c'est que lorsque le soft est en run-time, il n'y a pas d'exception levée si le pointeur est à 0, alors
qu'il ne devrait pas le permettre, si il le permet alors il y a un segfault qui se produit, ce qui est normal.

Dans mon cas, certainement un problème au niveau de la libstdc++ que j'essaierai de patcher ce soir.

Pourquoi n'ai-je pas fait de :
if (importFile.get()) {
...Traitements...
}

Parce que je pense qu'il est préférable de lancer une exception en cas de problème d'allocation mémoire.

Enfin, tout dépend de l'implémentation de new, new[].

bien à toi,

Stéphane


Avatar
adebaene
Stephane Wirtel wrote:


Concernant le compilateur, il s'agit soit de C++ Builder ou de GCC,
mais j'ai une plus grosse préférence pour GCC.


Quel que soit le compilateur (GCC, VC - pour BC il faudrait vérifier),
les versions récentes de ces compilos lèvent std::bad_alloc. Pour les
versions plus ancienens ,il faut vérifier.

Arnaud

Avatar
Alexandre
Quel que soit le compilateur (GCC, VC - pour BC il faudrait vérifier),
les versions récentes de ces compilos lèvent std::bad_alloc. Pour les
versions plus ancienens ,il faut vérifier.


sur C++ Builder 6 il me semble que new lève bad_alloc.. Difficile à essayer,
puisque sur mon système je n'ai encore jamais eu un new qui ne marche pas
(j'ai un gros disque dur vide, donc alouer 4GO ne lui pose pas de pb...)
ceci dit si je fais ça :

for(;;)
{
char *ptr_test;
try {
ptr_test= new char[4000000];
}
catch(std::bad_alloc)
{
std::cerr<<"nNEW leve une bad_alloc";
throw;
}
catch(...)
{
std::cerr<<"nTiens ? Une autre exception ?";
}
if'(ptr_test==0)
std::cerr<<"nFinalement, ça revoit 0 !";

}

je devrais savoir ;-)
je teste et je re-poste

Avatar
Stephane Wirtel
d'accord avec toi alexandre,

Je n'ai pas essayé ce code sous BCB6, parce qu'il s'agit d'un code d'essai et que je n'aurais pas pû l'intégrer dans le code actuel de l'application.

Mais cela me dérange tout de même que l'on puisse faire un "auto_ptr <TypeVariable> ptr (0)"

Parce que en pratique, si on fait ptr->Print (), ptr étant = 0, on obtient un SegFault.

N'y aurait-il pas un bug ?

Concernant Boost, est-ce qu'il existe des pointeurs intelligents ayant une meilleure conception ?

Stéphane
Avatar
kanze
Stephane Wirtel wrote:

Ce qui me fait peur, c'est que lorsque le soft est en
run-time, il n'y a pas d'exception levée si le pointeur est à
0, alors qu'il ne devrait pas le permettre, si il le permet
alors il y a un segfault qui se produit, ce qui est normal.


Selon la norme, l'operator new ne renvoie jamais NULL.

Selon le compilateur et le système, le comportement en cas
d'épuisement de la mémoire varie. Tous les versions récentes des
compilateurs essaient de lever bad_alloc, je crois, mais
certains systèmes d'exploitation ne leur aide pas. (La dernière
fois que j'ai essayé, ni Windows ni Linux ne signalait une
manque de mémoire correctement. Mais ça date ; les choses ont pu
évoluer depuis.)

Avec des compilateurs plus anciens, il faut se méfier plus. VC++
6.0 renvoyait encore NULL, il me semble, et g++ 2.95.2 abortait
le programme, sans plus. Dans ces cas-là, la solution évidente,
c'est de mettre à jour le compilateur. Sauf que si tu as du code
existant, ce n'est pas toujours si simple que ça.

--
James Kanze GABI Software
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
adebaene
Stephane Wirtel wrote:

Concernant Boost, est-ce qu'il existe des pointeurs intelligents
ayant une meilleure conception ?


Certainement! boost::shared_ptr est ton ami. Il est un poil plus lourd
que auto_ptr, mais il a une sémantique beaucoup plus "naturelle" et
aisée à mettre en oeuvre.

Arnaud

Avatar
kanze
Stephane Wirtel wrote:
d'accord avec toi alexandre,

Je n'ai pas essayé ce code sous BCB6, parce qu'il s'agit d'un
code d'essai et que je n'aurais pas pû l'intégrer dans le code
actuel de l'application.

Mais cela me dérange tout de même que l'on puisse faire un
"auto_ptr <TypeVariable> ptr (0)"

Parce que en pratique, si on fait ptr->Print (), ptr étant =
0, on obtient un SegFault.

N'y aurait-il pas un bug ?


Non. Le but, c'est d'émuler un pointeur classique:-).

Le problème, à mon avis, ce n'est pas tant qu'il permet des
pointeurs nuls, mais que la façon de les tester est un peu
maladroit :

if ( ptr.get() == NULL )

Idéalement, on aimerait écrire :

if ( ptr == NULL )

exactement comme pour un pointeur brut. Mais je ne sais pas
définir une classe qui supporte ça sans permettre la comparaison
soit avec n'importe quel entier soit avec n'importe quel
pointeur. (Dans mes propres classes, je supporte == et != avec
des T*. C'est peut-être la solution la plus tolérable.)

Concernant Boost, est-ce qu'il existe des pointeurs
intelligents ayant une meilleure conception ?


Ça veut dire quoi, une meilleure conception ? Il y a d'autres
pointeurs intelligents en Boost, avec d'autres sémantiques. Dans
la pratique, on a :

boost::scoped_ptr :
Le plus simple, il ne supporte pas la copie ni
l'affectation. Pour des membres des classes qui ne les
supportent pas non plus, c'est exactement ce qu'il faut. Ne
peut pas servir dans des collections STL.

std::auto_ptr :
À utiliser chaque fois qu'un transfert de responsibilités
est désiré. Valeur de retour d'une fonction, évidemment,
mais il me sert aussi quand je passe des objets entre des
threads. Ne peut pas servir dans des collections STL.

boost::shared_ptr/boost::weak_ptr :
Beaucoup plus complexe et lourd, mais avec une sémantique de
responsibilité partagée. Avec un peu d'attention, peut
remplacer un glaneur de cellules dans beaucoup de cas. C'est
donc le plus complet -- mais le plus complexe à utiliser
aussi, du fait qu'il y a deux types de pointeurs. (Il y a
aussi des problèmes quand on doit convertir le pointeur brut
en un pointeur intelligent à plusieurs endroits différents.)

pointeur à comptage de références invasifs :
Pas de standard, mais dans la mésure que les exemples ont
aparus dans plusieurs livres (dont Scott Meyers), il est
assez repandu. En gros, l'utilisation récouvre celle de
boost::shared_ptr, sans les weak_ptr, avec un mechanisme
bien moins lourd et plus robuste, mais avec le désavantage
non-negligeable qu'il faut que l'objet auquel il pointe
dérive d'une classe prédéfinie (RefCntObj, RfObject, ou
quelque chose du genre).

Il y a aussi sans doute bien d'autres variantes.

Les pointeurs boost ont aussi la particularité qu'on peut leur
spécifier que faire lors de la « destruction ». On pourrait donc
imaginer un boost::shared_ptr qui, à la place de détruire
l'objet, libérer seulement un lock.

--
James Kanze GABI Software
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

1 2