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

Savoir si une classe a ete cree par new

28 réponses
Avatar
dug8C
Bonjour,

J'ai besoin de savoir si une classe est cree sur la pile ou sur le
tas.
J'ai definit un booleen qui porte cette indication, et qui est
renseign=E9 au moment de la creation par une focntoin new priv=E9e


// le fichier h
class CBase1
{

public:

CBase1(const std::string& name);
CBase1(const CBase1& autre);
CBase1& operator=3D(const CBase1& autre);
virtual ~CBase1();

void* operator new( unsigned bytes )
{
// std::cout << "operator new( unsigned bytes )" <<
std::endl;
void* result =3D malloc(bytes);
if (result =3D=3D NULL)
throw std::bad_alloc();
else
{
creation_dyn =3D true;
return result;
}
}

void operator delete (void* p )
{
free(p);
}

// -----
std::string Name() const ;
// renvoie la trace de la creation sur la pile ou sur le tas
bool Dyn_Created() const { return cree_dyn; }

//--- operator

virtual bool operator=3D=3D(const CBase1& autre);

// --
static bool creation_dyn;
protected:
// identifiant
std::string m_name;
// trace de la creation sur la pile ou sur le tas
bool cree_dyn;

virtual void Copy( const CBase1& autre);
};

// -- le fichier cpp
CBase1::CBase1(const std::string& name)
: m_name(name)
{

std::cout << "CBase1 CTOR (" << m_name << ", " << this << ")" <<
std::endl;
cree_dyn =3D creation_dyn;
creation_dyn =3D false;
}

CBase1::CBase1(const CBase1& autre)
{
Copy(autre);
}
CBase1& CBase1::operator=3D(const CBase1& autre)
{
Copy(autre);
return *this;
}
CBase1::~CBase1()
{
std::cout << "CBase1 DTOR (" << m_name << ", " << this << ")" <<
std::endl;
}


std::string CBase1::Name() const
{
return m_name;
}

bool CBase1::operator=3D=3D(const CBase1& autre)
{
// test d'=E9galit=E9 sur les noms pas sur la facon dont la ressource a
=E9t=E9 cr=E9=E9e
return ( autre.m_name =3D=3D m_name );
}

void CBase1::Copy( const CBase1& autre)
{
if( &autre !=3D this )
{
// ne pas copier cree_dyn !
m_name =3D autre.m_name;
}
}

Ca marche plutot bien en apparence, et je me sert de cette classe
comme base pour le polymorphisme.

Par contre j'ai une interrogation, y a t il une autre facon de faire?
J'ai utilis=E9 malloc et free, car la fonction globale new appelle une
2eme fois le constructeur ce qui est genant.

10 réponses

1 2 3
Avatar
Fabien LE LEZ
On 23 Mar 2007 18:26:54 -0700, :

J'ai besoin de savoir si une classe est cree sur la pile ou sur le
tas.


Juste par curiosité, pourquoi donc as-tu besoin de le savoir ?

Avatar
James Kanze
On Mar 24, 2:26 am, wrote:

J'ai besoin de savoir si une classe est cree sur la pile ou
sur le tas.


C'est impossible de façon portable. Sur beaucoup de systèmes, en
revanche, la pile se trouve à des adresses connues, et la
comparaison d'adresse marche : une solution fréquente sur Sparc
ou sur PC, c'est de mettre la pile tout en haut de l'espace
adresse ; puisque la pile croît vers le bas sur ces deux
processeurs, si l'adresse est supérieur à l'adresse d'une
variable locale, elle est sur la pile.

Traditionnellement aussi les Unix définissait un symbole
« end », à la fin de la mémoire statique. Donc, sur un PC (au
moins sous Linux) ou sur un Sparc :

char const*
located(
void* p )
{
extern int end ;
if ( p > &p ) {
return "local" ;
} else if ( p < &end ) {
return "static" ;
} else {
return "dynamic" ;
}
}

(En revanche, je sais que ça ne marche pas du tout sur les PA de
HP.)

Aussi, évidemment, ça ne marche que dans le cas des programmes
mono-thread. Dans un environement multi-thread, chaque processus
a sa propre pile, typiquement allouée sur le tas.

J'ai definit un booleen qui porte cette
indication, et qui est renseigné au moment de la creation par
une focntoin new privée


C'est la solution classique. Ça ne permet toujours pas de
distinguer entre les variables locales et les statiques, ce
n'est pas thread-safe, et ça ne marche pas si les objets se
trouvent dans un tableau (c-à-d alloués avec new[]).

[...]
Ca marche plutot bien en apparence, et je me sert de cette classe
comme base pour le polymorphisme.


C'est que tu n'en as pas essayé les cas que j'ai énumérés
ci-dessus.

Par contre j'ai une interrogation, y a t il une autre facon de faire?
J'ai utilisé malloc et free, car la fonction globale new appelle une
2eme fois le constructeur ce qui est genant.


La fonction new n'appelle de constructeur. C'est une expression
new qui l'appelle. Donc :

p = new Toto ; // appel du constructeur...
p = operator new( sizeof Toto ) ;
// pas d'appel du constructeur...


La même dichotomie existe entre la fonction delete, et une
experssion delete.

--
James Kanze (Gabi Software) email:
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
dug8C
On 24 mar, 02:32, Fabien LE LEZ wrote:
On 23 Mar 2007 18:26:54 -0700, :

J'ai besoin de savoir si une classe est cree sur la pile ou sur le
tas.


Juste par curiosité, pourquoi donc as-tu besoin de le savoir ?


En fait j'ai crée une classe qui manipule la classe CBase1 et qui gère
la libération de la mémoire.
J'ai besoin de savoir si je dois appeller delete si CBase1 est créée
sur le tas.


Avatar
Fabien LE LEZ
On 24 Mar 2007 02:54:51 -0700, :

J'ai besoin de savoir si je dois appeller delete si CBase1 est créée
sur le tas.


Utilise un GC, et comme ça tu n'auras jamais besoin d'appeler delete.

Avatar
dug8C
On 24 mar, 09:35, "James Kanze" wrote:
On Mar 24, 2:26 am, wrote:

J'ai besoin de savoir si une classe est cree sur la pile ou
sur le tas.


C'est impossible de façon portable. Sur beaucoup de systèmes, en
revanche, la pile se trouve à des adresses connues, et la
comparaison d'adresse marche : une solution fréquente sur Sparc
ou sur PC, c'est de mettre la pile tout en haut de l'espace
adresse ; puisque la pile croît vers le bas sur ces deux
processeurs, si l'adresse est supérieur à l'adresse d'une
variable locale, elle est sur la pile.


Merci pour ces explications, mais comment fait-on pour mettre la pile
en haut de l'espace adresse ?
Je ne pensais pas qu'on pouvait le modifier

[...]

Ca marche plutot bien en apparence, et je me sert de cette classe
comme base pour le polymorphisme.


C'est que tu n'en as pas essayé les cas que j'ai énumérés
ci-dessus.


Effectivement je n'ai pas essayé les creations avec new[] , ni en
multi-thread
Dans ces cas là, existe -il une solution ?


Par contre j'ai une interrogation, y a t il une autre facon de faire?
J'ai utilisé malloc et free, car la fonction globale new appelle une
2eme fois le constructeur ce qui est genant.


La fonction new n'appelle de constructeur. C'est une expression
new qui l'appelle. Donc :

p = new Toto ; // appel du constructeur...
p = operator new( sizeof Toto ) ;
// pas d'appel du constructeur...

La même dichotomie existe entre la fonction delete, et une
experssion delete.

Ok, je vois que j'utilisais mal la fonction new.



Avatar
dug8C
On 24 mar, 11:02, Fabien LE LEZ wrote:
On 24 Mar 2007 02:54:51 -0700, :

J'ai besoin de savoir si je dois appeller delete si CBase1 est créée
sur le tas.


Utilise un GC, et comme ça tu n'auras jamais besoin d'appeler delete.


Oui j'y ai pensé aussi mais d'après que ce j'en sais le GC est un
"ramasse-miette" , c'est à dire qu'il ne libere la mémoire qu'à la fin
du programme ?

Mais si j'alloue de grande quantité de memoire ( par rapport à la
memoire disponible ) et que je libère qu'à la fin, tout le long du
programme de la memoire sera allouée alors qu'elle ne sert peut-être
pas ?


Avatar
Fabien LE LEZ
On 24 Mar 2007 03:18:10 -0700, :

Oui j'y ai pensé aussi mais d'après que ce j'en sais le GC est un
"ramasse-miette" ,


Oui.

c'est à dire qu'il ne libere la mémoire qu'à la fin
du programme ?


Non. Ça, c'est fait par l'OS de toutes façons, quel que soit le
programme.

Un GC est censé libérer la mémoire dès qu'un objet n'est plus utilisé.

Avatar
Fabien LE LEZ
On 24 Mar 2007 03:08:51 -0700, :

Merci pour ces explications, mais comment fait-on pour mettre la pile
en haut de l'espace adresse ?


Comme l'a dit James, ça dépend de l'OS. Il faut donc t'intéresser à
l'API de ton OS.
Mais du coup, tu perds la portabilité.

Avatar
Loïc Joly

Un GC est censé libérer la mémoire dès qu'un objet n'est plus utilisé.


Pas "dès qu'", mais "à un moment après qu'... s'il en a envie".

--
Loïc

Avatar
James Kanze
On Mar 24, 3:03 pm, Loïc Joly
wrote:

Un GC est censé libérer la mémoire dès qu'un objet n'est plus u tilisé.


Pas "dès qu'", mais "à un moment après qu'... s'il en a envie".


Ça dépend de ce que tu entends par « libérer ».

D'abord, ni les glaneurs de cellules, ni les implémentations de
malloc/free que j'utilise ne libèrent la mémoire au système.
Strictement parlant, ils ne la libèrent jamais ; ils
s'arrangent pour le réutiliser dans le processus même. Si un
processus utilise beaucoup de mémoire dynamique pendant une
courte durée, cette mémoire reste « perdue » jusqu'à la fin du
processus. En principe, et un glaneur de cellules et
malloc/free pourraient libérer la mémoire au système. Dans la
pratique, en revanche, ça ne marche bien que dans le cas des
glaneurs de cellules qui déplacent la mémoire (et qui donc
finissent par avoir toute la mémoire libre dans un bloc unique),
et de tels glaneurs de cellules ne marchent pas réelement avec
le C++.

Ensuite, évidemment, à l'intérieur du processus... la mémoire
est libérée dans la mesure où elle est disponible lors de la
prochaine démande d'allocation. C'est vrai qu'avec un glaneur de
cellules, on ne la réutilisera qu'après un passage par le
collecteur, qui ne sera déclenché que s'il y a besoin. Mais dans
la pratique, certains malloc/free ne se comportent pas
différemment -- la seule différence, c'est qu'avec le
malloc/free, c'est l'appel de free qui positionne le drappeau
que le bloc est libre, tandis qu'un glaneur de cellules s'en
aperçoit tout seul. (Pour des raisons de mise au point, il est
souvent préférable de ne pas récycler la mémoire tout de suite,
et des outils tel que Purify la retient aussi longtemps que
possible avant de la réutiliser.)

--
James Kanze (Gabi Software) email:
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 3