OVH Cloud OVH Cloud

new et bad_alloc

28 réponses
Avatar
pasde.bcausse.spam
bonsoir, je reviens avec mon probleme.

class RX_A {

public :
unsigned long l;
unsigned char m;
unsigned char d;
signed char bas;
signed char haut;
};

class RX_B{

public :
RX_A premier;
RX_A second;
};


class RX_C {

RX_B* table;

public:

RXHashTable();
~RXHashTable();

};

dans RX_C.cpp

RX_C::RX_C() : table(0) {

const unsigned long capacity = 1<<31; //2147483648

try {
table = new RX_B[capacity];

if(table == 0)
std::cerr << "table = 0 -> RX_C::RX_C: cannot
allocate the table\n";

} catch (const std::bad_alloc &e_ba) {
std::cerr << "RX_C::RX_C: cannot allocate the
table\n";
throw;
}


}

non seulement table != 0 mais aucune exception bad_alloc est levée.

comprends pas :-(


--
Bruno Causse
http://perso.wanadoo.fr/othello

10 réponses

1 2 3
Avatar
Bruno CAUSSE
dans l'article ,
à a écrit le 26/05/05 10:05 :

De toute façon, si son problème, c'est simplement de tester le
comportement de son code en cas d'épuisement de la mémoire,


Je debute, alors je suis une regle (recommandation) de verifier que
l'allocation n'echoue pas. Et j'essaye de le faire avec la "philosophie" C++
(bad_alloc) plutot que == NULL.

Mais cela me servira a liberer les ressources (fichers, sockets ...) avant
de quitter le prog.

Avatar
Gabriel Dos Reis
writes:

| Jean-Marc Bourguet wrote:
| > (Bruno Causse) writes:
|
| > > const unsigned long capacity = 1<<31; //2147483648
|
| > C'est peut-etre un peu trop... un probleme possible est que
|
| > capacite*sizeof(RX_B)
|
| > est fait sans verifier le depassement de capacite (::operator
| > new ne voit qu'un size_t, donc ne peut pas le detecter, il
| > faut que ce soit fait ailleurs) qui resulte en une taille
| > possible.
|
| Est-ce qu'il y a eu un DR là-dessus, avec une décision du
| comité@? Parce que la norme est claire : quelque soit le nombre
| d'éléments que tu passes à l'expression new, ou bien, elle les
| alloue, ou bien, elle lève l'exception bad_alloc.
|
| Mais évidemment, aucune implémentation ne le fait. Et ça pose
| des problèmes à l'implémentation -- parce que les tests de
| débordement, il faut que ce soit avant l'appel de la fonction
| operator new qu'ils aient lieu, mais qu'en cas de débordement,
| il faut que le comportement soit exactement celui de la fonction
| operator new. Y compris si la fonction operator new a été
| remplacée par l'utilisateur.

N'avions-nous pas déjà discuté de ceci ici même, forwardé au comité,
bug report à GCC sans succès ?

-- Gaby
Avatar
Pierre THIERRY
Le Thu, 26 May 2005 00:14:41 +0200, Fabien LE LEZ a écrit :
Y a-t-il des cas où on doit vraiment attraper bad_alloc ?
Généralement, ça veut dire que le système est dans un tel état que le
programme ne peut de toutes façons pas continuer.


Pas forcément. Un algo peut très bien décider de fractionner les données
en cas de bad_alloc. Ça pourrait très bien être un algo récursif dans ce
goût-là :

template<typename RandomIterator, typename UnaryOperation>
void Splitter (UnaryOperation func, RandomIterator start, RandomIterator end)
{
try
{
func(start, end);
}
catch(bad_alloc)
{
RandomIterator middle = (start + (end - start) / 2);
func(start, middle);
func(middle + 1, end);
}
}

D'ailleurs, ne connaissant convenablement ni les exceptions ni les
distances d'itérateur, est-ce que ce bout de code semble, à ceux qui
connaissent, correct ?

Suggestivement,
Nowhere man
--

OpenPGP 0xD9D50D8A

Avatar
Jean-Marc Bourguet
writes:

Jean-Marc Bourguet wrote:
Fabien LE LEZ writes:

On Wed, 25 May 2005 23:27:30 +0200,
(Bruno Causse):

je voulais tester le declenchement d'une exception
bad_alloc, suite a l'echec de new.


Y a-t-il des cas où on doit vraiment attraper bad_alloc ?
Généralement, ça veut dire que le système est dans un tel
état que le programme ne peut de toutes façons pas
continuer.


Je ne vois pas en quoi bad_alloc est different des autres
exceptions.


Parce que le système d'exploitation y a son mot à dire, peut-être ?


Ca veut dire qu'on ne recoit pas bad_alloc quand on le devrait, ca
n'indique rien sur l'etat du programme quand cette exception est
jetee.

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




Avatar
Fabien LE LEZ

Y a-t-il des cas où on doit vraiment attraper bad_alloc ?



En fait, j'aurais dû dire "Y a-t-il des cas où on doit vraiment
attraper explicitement bad_alloc ?"

(i.e. faire un "catch (bad_alloc)")

James :
mais dans toutes les applications robustes, la fonction
main n'est qu'un bloc try, avec un catch( ... ) à la fin,
précisement pour cette raison.


C'est également ce que je fais. Mais bad_alloc est perdue dans la
masse des "exceptions irrécupérables", i.e. "catch (std::exception)"
ou "catch (...)", avec juste un message éventuel et une sortie du
programme.

En pratique, si une opération demandée par l'utilisateur genère un
bad_alloc, je considère que le système est trop instable pour assurer
un comportement décent de l'application, et je ne me fatigue donc pas
à tenter de le continuer.

Note que je fais principalement des applications GUI, i.e. avec
interaction directe, pas des applications serveurs.

Ma question était donc : est-ce que j'ai raison de faire comme ça, ou
faut-il que je change mes méthodes ?


Avatar
Fabien LE LEZ
On Thu, 26 May 2005 10:24:34 +0200, Bruno CAUSSE :

Mais cela me servira a liberer les ressources (fichers, sockets ...) avant
de quitter le prog.


Note qu'un OS décent est censé être capable de fermer les ressources
lors de la fermeture d'un process (y compris la fermeture brutale, par
kill sous Unix ou le gestionnaire des tâches sous Windows), voire même
de supprimer les fichiers temporaires.

En pratique, il y a même des chances pour que le processus soit tué
par l'utilisateur plus souvent qu'il ne rencontrera un bad_alloc.

Avatar
James Kanze
Bruno Causse wrote:

const unsigned long capacity = 1<<31; //2147483648


Une petite question sécondaire : capacity, est-ce qu'il doit
avoir la valeur 2147483648, ou est que tu veux une valeur avec
le bit 31 à 1, et les autres à zéro ?

Je sais que c'est la même chose à la fin, mais conceptuellement,
il y a une différence. Alors, on se sert de celui qu'on veut à
l'initialisation, et on ne met pas de commentaire pour faire
penser que peut-être on voulait l'autre.

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Avatar
James Kanze
Jean-Marc Bourguet wrote:
writes:


Jean-Marc Bourguet wrote:



Fabien LE LEZ writes:




On Wed, 25 May 2005 23:27:30 +0200,
(Bruno Causse):





je voulais tester le declenchement d'une exception
bad_alloc, suite a l'echec de new.






Y a-t-il des cas où on doit vraiment attraper bad_alloc ?
Généralement, ça veut dire que le système est dans un tel
état que le programme ne peut de toutes façons pas
continuer.





Je ne vois pas en quoi bad_alloc est different des autres
exceptions.




Parce que le système d'exploitation y a son mot à dire,
peut-être ?



Ca veut dire qu'on ne recoit pas bad_alloc quand on le
devrait, ca n'indique rien sur l'etat du programme quand cette
exception est jetee.


Oui et non. Solaris 2.2, avant de réfuser l'allocation, était
tellement aux limites qu'il se bloquait. Même mon système
actuel, au travail, tourne au rallenti (au point de devenir
penible) bien avant de lever un bad_alloc. (Juste avant de
partir ce soir, j'ai lancé un processus qui a besoin d'environ
un démi-méga. Parce que la machine n'a que 256 Mo réel, et
lorsque je lance ce processus, elle s'arrête, ou prèsque.)

Qu'on le veuille ou non, la gestion de l'épuissement de la
mémoire est autre qu'une exception classique. Au moins sur
certains systèmes, dans certaines conditions. (Mais je n'irais
pas à l'extrème de Fabien, pour dire que ce n'a jamais de sens.
C'est un « tout dépend ».)

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34





Avatar
James Kanze
Fabien LE LEZ wrote:

Y a-t-il des cas où on doit vraiment attraper bad_alloc ?




En fait, j'aurais dû dire "Y a-t-il des cas où on doit
vraiment attraper explicitement bad_alloc ?"


(i.e. faire un "catch (bad_alloc)")


James :


mais dans toutes les applications robustes, la fonction
main n'est qu'un bloc try, avec un catch( ... ) à la fin,
précisement pour cette raison.



C'est également ce que je fais. Mais bad_alloc est perdue dans
la masse des "exceptions irrécupérables", i.e. "catch
(std::exception)" ou "catch (...)", avec juste un message
éventuel et une sortie du programme.


En pratique, si une opération demandée par l'utilisateur
genère un bad_alloc, je considère que le système est trop
instable pour assurer un comportement décent de l'application,
et je ne me fatigue donc pas à tenter de le continuer.


Note que je fais principalement des applications GUI, i.e.
avec interaction directe, pas des applications serveurs.


Ma question était donc : est-ce que j'ai raison de faire comme
ça, ou faut-il que je change mes méthodes ?


Comme j'ai dit à Jean-Marc, tout dépend. Je suis scéptique en ce
qui concerne le bad_alloc dans le cas général, mais je reconnais
bien qu'il y a des exceptions. Dans l'application où je
travaille actuellement, un bad_alloc ne peut être qu'une erreur
fatale. Et sérieuse -- au moins qu'il provient d'une fuite de
mémoire (et on passe le programme à Purify lors des tests), non
seulement est-il fatal au processus, il empèche le relancement
du processus. (Pratiquement toutes nos données sont
persistentes. Ce qui veut dire qu'au relancement, on les
récharge -- et on se rétrouve dans la même situation.)

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34



Avatar
James Kanze
Gabriel Dos Reis wrote:
writes:


| Jean-Marc Bourguet wrote:
| > (Bruno Causse) writes:


| > > const unsigned long capacity = 1<<31;
//2147483648


| > C'est peut-etre un peu trop... un probleme possible est que


| > capacite*sizeof(RX_B)


| > est fait sans verifier le depassement de capacite
| > (::operator new ne voit qu'un size_t, donc ne peut pas le
| > detecter, il faut que ce soit fait ailleurs) qui resulte
| > en une taille possible.


| Est-ce qu'il y a eu un DR là-dessus, avec une décision du
| comité@? Parce que la norme est claire : quelque soit le
| nombre d'éléments que tu passes à l'expression new, ou bien,
| elle les alloue, ou bien, elle lève l'exception bad_alloc.


| Mais évidemment, aucune implémentation ne le fait. Et ça
| pose des problèmes à l'implémentation -- parce que les tests
| de débordement, il faut que ce soit avant l'appel de la
| fonction operator new qu'ils aient lieu, mais qu'en cas de
| débordement, il faut que le comportement soit exactement
| celui de la fonction operator new. Y compris si la fonction
| operator new a été remplacée par l'utilisateur.


N'avions-nous pas déjà discuté de ceci ici même, forwardé au
comité, bug report à GCC sans succès ?


C'est ce qu'il me semblait (ici ou ailleurs, je ne m'en souviens
pas). Mais n'étant pas sûr...

La question reste : qu'est-ce que le comité décide ? Parce que
s'il veut permettre le comportement actuel, il faut bien changer
la formulation dans la norme, et bien indiquer où sont les
limites. Ou est-ce qu'on accepte que quelque chose comme :

struct S {} ;

S* p = new S[ 2 ] ;

a un comportement indéfini ?

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

1 2 3