OVH Cloud OVH Cloud

allocation/desallocation dans le tas au sein d'un même bloc

12 réponses
Avatar
Olivier Azeau
Dans un thread récent, il a été mentionné à juste titre qu'on ne doit
jamais écrire :
{
A *a = new A;
delete a;
}
mais :
{
A a;
}

Cependant, il y a un cas où on l'écrit sans pouvoir y faire grand chose.
Quand la classe A est une interface publique qui implémente une
technique d'isolement pour éviter les problèmes de compatibilité binaire :

class ImplA
{
int x;
double y;
...
}

class A
{
ImplA *impl;
public:
A() { impl = new ImplA; }
~A() { delete impl; }
};

Existe-t-il des techniques qui permettent de minimiser l'impact des
allocations dans le tas pour un tel cas ?

10 réponses

1 2
Avatar
Christophe Lephay
"Olivier Azeau" a écrit dans le message de news:
egcvd.3828$
Cependant, il y a un cas où on l'écrit sans pouvoir y faire grand chose.
Quand la classe A est une interface publique qui implémente une technique
d'isolement pour éviter les problèmes de compatibilité binaire :

class ImplA
{
int x;
double y;
...
}

class A
{
ImplA *impl;
public:
A() { impl = new ImplA; }
~A() { delete impl; }
};

Existe-t-il des techniques qui permettent de minimiser l'impact des
allocations dans le tas pour un tel cas ?


L'intérêt de la pile, c'est qu'elle est locale et facile à nettoyer. Lorsque
cette "localité" n'apporte rien, je ne vois pas pourquoi ce serait mieux de
créer l'objet sur la pile plutôt que sur le tas. En l'occurrence, dans
l'exemple que tu donnes, la durée de vie dépasse le cadre de la fonction,
raison de plus pour que la pile n'apporte rien (ce serait même plutôt le
contraire).

Enfin il faut voir ce que tu appelles "l'impact des allocations dans le
tas", qui est excessivement flou pour moi.

Sinon, au pire, il y a le new de placement...

Chris

Avatar
Luc Hermitte
Olivier Azeau wrote in
news:egcvd.3828$:

[... idiome pimpl ; compilation firewall ; ... ]

class ImplA
{
int x;
double y;
...
}

class A
{
ImplA *impl;
public:
A() { impl = new ImplA; }
~A() { delete impl; }
};

Existe-t-il des techniques qui permettent de minimiser l'impact des
allocations dans le tas pour un tel cas ?


Tu as des items de GOTW/XC++, qui sont consultables sur le site d'Herb
Sutter, qui traitent de cela.

--
Luc Hermitte <hermitte at free.fr>
FAQ de <news:fr.comp.lang.c++> :
<http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/>
Dejanews : <http://groups.google.com/advanced_group_search>

Avatar
Loïc Joly
Olivier Azeau wrote:

class ImplA
{
int x;
double y;
...
}

class A
{
ImplA *impl;
public:
A() { impl = new ImplA; }
~A() { delete impl; }
};

Existe-t-il des techniques qui permettent de minimiser l'impact des
allocations dans le tas pour un tel cas ?


Dans ce genre de cas, je déclare impl en tant que :

std::auto_ptr<ImplA> const impl;

Ou :

boost::scoped_ptr<ImplA> impl;

Je préfère la seconde, plus explicite, mais elle demande à utiliser boost.

(remarque : Ne pas oublier : Le destructeur doit être non par défaut et
défini dans le .cpp. En effet, le destructeur par défaut, inline,
demande à connaitre le type complet ImplA)
--
Loïc

Avatar
Loïc Joly
Olivier Azeau wrote:

class ImplA
{
int x;
double y;
...
}

class A
{
ImplA *impl;
public:
A() { impl = new ImplA; }
~A() { delete impl; }
};

Existe-t-il des techniques qui permettent de minimiser l'impact des
allocations dans le tas pour un tel cas ?


Dans ce genre de cas, je déclare impl en tant que :

std::auto_ptr<ImplA> const impl;

Ou :

boost::scoped_ptr<ImplA> impl;

Si A est copiable, j'utilise ma propre classe de pointeurs intelligents
qui fait une copie profonde.

Je préfère la seconde, plus explicite, mais elle demande à utiliser boost.

(remarque : Ne pas oublier : Le destructeur doit être non par défaut et
défini dans le .cpp. En effet, le destructeur par défaut, inline,
demande à connaitre le type complet ImplA)

--
Loïc

Avatar
Arnaud Debaene
Loïc Joly wrote:
Olivier Azeau wrote:

class ImplA
{
int x;
double y;
...
}

class A
{
ImplA *impl;
public:
A() { impl = new ImplA; }
~A() { delete impl; }
};

Existe-t-il des techniques qui permettent de minimiser l'impact des
allocations dans le tas pour un tel cas ?


Dans ce genre de cas, je déclare impl en tant que :

std::auto_ptr<ImplA> const impl;

Ou :

boost::scoped_ptr<ImplA> impl;
Cela limite le risque d'oubli de désallocation (en cas d'exception

notamment), mais ca ne résoud pas les problèmes de fragmentation mémoire, de
manque de localité, etc... Ceci-dit, je ne sais pas ce qu'Olivier avait en
tête quand il parlait de "l'impact" des allocations dynamiques.

Arnaud


Avatar
Fabien LE LEZ
On Mon, 13 Dec 2004 21:57:06 +0100, "Arnaud Debaene"
:

Ceci-dit, je ne sais pas ce qu'Olivier avait en
tête quand il parlait de "l'impact" des allocations dynamiques


Le seul problème que je vois, c'est que l'allocation dynamique est
gourmande en temps. Ceci dit, il reste à prouver que l'impact en
question est mesurable...

--
;-)

Avatar
Gabriel Dos Reis
Fabien LE LEZ writes:

| On Mon, 13 Dec 2004 21:57:06 +0100, "Arnaud Debaene"
| :
|
| >Ceci-dit, je ne sais pas ce qu'Olivier avait en
| >tête quand il parlait de "l'impact" des allocations dynamiques
|
| Le seul problème que je vois, c'est que l'allocation dynamique est
| gourmande en temps. Ceci dit, il reste à prouver que l'impact en
| question est mesurable...

Mais en C++, on peut toujours redéfinir sa propre fonction d'allocation.
Ceci dit, j'ai toujours trouvé le glaneur de cellule natif de C assez
efficace.

-- Gaby
Avatar
Olivier Huet
Bonjour,



Existe-t-il des techniques qui permettent de minimiser l'impact des
allocations dans le tas pour un tel cas ?



Ca dépends de l'impact : par exemple, si c'est de la contention en
environement multiprocesseurs dans des applications multithreadées, il y
a des librairies d'allocation dédiées à ce genre d'environnement - par
exemple, Hoard ou SmartHeap.

Hoard est sur :

http://www.hoard.org/


En fait, je ne peux pas vraiment donner de retour sur expérience, car
nous avons seulement *envisagé* son utilisation.


Olivier Huet

Avatar
Olivier Azeau
Gabriel Dos Reis wrote:
Fabien LE LEZ writes:

| On Mon, 13 Dec 2004 21:57:06 +0100, "Arnaud Debaene"
| :
|
| >Ceci-dit, je ne sais pas ce qu'Olivier avait en
| >tête quand il parlait de "l'impact" des allocations dynamiques
|
| Le seul problème que je vois, c'est que l'allocation dynamique est
| gourmande en temps. Ceci dit, il reste à prouver que l'impact en
| question est mesurable...

Mais en C++, on peut toujours redéfinir sa propre fonction d'allocation.
Ceci dit, j'ai toujours trouvé le glaneur de cellule natif de C assez
efficace.



Oui, je voulais dire l'impact sur les performances (temps, consommation
CPU, ...)
Et l'impact est mesurable : il suffit d'essayer hoard ou ptmalloc pour
s'en convaincre.

Mais je me suis mal exprimé au départ. Je ne me place pas en fait dans
un contexte où j'ai une grande latitude sur la classe A (pour diverses
raisons, la principale étant que, dans bien des cas, elle provient d'un
tiers)
Ce que je me demande c'est comment faire a posteriori : j'ai une classe
A dont l'instanciation "coute" et je veux pouvoir, sans trop me prendre
la tête, l'utiliser comme une classe dont l'instanciation coute beaucoup
moins.
Ma 1ère idée c'est de wrapper la classe par une classe PooledA dont
l'instanciation tire parti d'un ensemble réutilisable d'instances de A.
Le problème c'est que ça devient vite un enfer si on veut dériver A, si
on veut prendre en compte que certaines méthodes ne supportent pas la
réutilisation d'instance, ...

Olivier

Avatar
Gabriel Dos Reis
Olivier Azeau writes:

| Gabriel Dos Reis wrote:
| > Fabien LE LEZ writes:
| > | On Mon, 13 Dec 2004 21:57:06 +0100, "Arnaud Debaene"
| > | :
| > | | >Ceci-dit, je ne sais pas ce qu'Olivier avait en | >tête quand
| > il parlait de "l'impact" des allocations dynamiques
| > | | Le seul problème que je vois, c'est que l'allocation dynamique
| > est
| > | gourmande en temps. Ceci dit, il reste à prouver que l'impact en
| > | question est mesurable...
| > Mais en C++, on peut toujours redéfinir sa propre fonction
| > d'allocation.
| > Ceci dit, j'ai toujours trouvé le glaneur de cellule natif de C assez
| > efficace.
|
| Oui, je voulais dire l'impact sur les performances (temps,
| consommation CPU, ...)
| Et l'impact est mesurable : il suffit d'essayer hoard ou ptmalloc pour
| s'en convaincre.
|
| Mais je me suis mal exprimé au départ. Je ne me place pas en fait dans
| un contexte où j'ai une grande latitude sur la classe A (pour diverses
| raisons, la principale étant que, dans bien des cas, elle provient
| d'un tiers)
| Ce que je me demande c'est comment faire a posteriori : j'ai une
| classe A dont l'instanciation "coute" et je veux pouvoir, sans trop me
| prendre la tête, l'utiliser comme une classe dont l'instanciation
| coute beaucoup moins.
| Ma 1ère idée c'est de wrapper la classe par une classe PooledA dont
| l'instanciation tire parti d'un ensemble réutilisable d'instances de A.

C'est ce que je disais dans mon précédent message. Tu peux rédéfinir
la fonction d'allocation « operator new » pour utiliser ta « pool ».
Elle peut être aussi rapide que l'incrémentation d'un pointeur.

| Le problème c'est que ça devient vite un enfer si on veut dériver A,
| si on veut prendre en compte que certaines méthodes ne supportent pas
| la réutilisation d'instance, ...

Là je ne te suis plus...

|
| Olivier

--
Gabriel Dos Reis

1 2