OVH Cloud OVH Cloud

Initialisation statique

15 réponses
Avatar
Guillaume LEMAÎTRE
Bonjour

J'aimerai savoir s'il existe des stratagèmes pour qu'une instance
constante d'une classe soit directement initialisée dans l'exécutable et
ne nécessite pas l'appel de constructeurs globaux.

Pour faire plus clair :

-->

class Biniou {
int a;
char b;

public :

const int get_a( void ) const { return a; };
const char get_b( void ) const { return b; };

int & set_a( void ) { return a; };
char & set_b( void ) { return b; };
};

// ligne invalide, mais qui veut bien dire ce qu'elle veut dire

const Biniou wesh = { 5, 'c' };

<--

La surcharge du constructeur amènerait à une initialisation dynamique et
non statique. Aujourd'hui j'en suis réduit à patcher la section 'data'
de l'exécutable pour réaliser mes initialisations, ce qui est efficace
mais peu propre...
Donc si l'un d'entre vous a une idée, elle est la bienvenue

PS: les initalisations peuvent être citiques dans le cas de programmes
temps-réel embarqués.

10 réponses

1 2
Avatar
Benoit Rousseau
Guillaume LEMAÎTRE wrote:
Bonjour

J'aimerai savoir s'il existe des stratagèmes pour qu'une instance
constante d'une classe soit directement initialisée dans l'exécutable et
ne nécessite pas l'appel de constructeurs globaux.

Pour faire plus clair :

-->

class Biniou {
int a;
char b;

public :

const int get_a( void ) const { return a; };
const char get_b( void ) const { return b; };

int & set_a( void ) { return a; };
char & set_b( void ) { return b; };
};

// ligne invalide, mais qui veut bien dire ce qu'elle veut dire

const Biniou wesh = { 5, 'c' };

<--

La surcharge du constructeur amènerait à une initialisation dynamique et
non statique. Aujourd'hui j'en suis réduit à patcher la section 'data'
de l'exécutable pour réaliser mes initialisations, ce qui est efficace
mais peu propre...
Donc si l'un d'entre vous a une idée, elle est la bienvenue

PS: les initalisations peuvent être citiques dans le cas de programmes
temps-réel embarqués.

Un truc moins "ch**nt" que de patcher la section data serait peut-être :


char tmp[5] = { 5, 0, 0, 0, 'c' };
Biniou* b = (Biniou*)tmp;

Mais je ne pense pas que ce soit la même valeur pour tous les systèmes,
et c'est toujours aussi nul à maintenir...


--------------------------------------------
Benoît Rousseau : roussebe at spray dot se
Jouez en programmant : http://realtimebattle.sourceforge.net/

Avatar
Loïc Joly
Guillaume LEMAÎTRE wrote:
La surcharge du constructeur amènerait à une initialisation dynamique et
non statique.


Je ne vois pas pourquoi. Peux-tu expliciter ce que tu veux dire ?

--
Loïc

Avatar
Guillaume LEMAÎTRE
Loïc Joly wrote:
Guillaume LEMAÎTRE wrote:

La surcharge du constructeur amènerait à une initialisation dynamique
et non statique.



Je ne vois pas pourquoi. Peux-tu expliciter ce que tu veux dire ?



à supposer que l'on ait en plus :

-->

class Biniou {

// ...

Biniou( const int p_a, const char p_b ) :
a( p_a ),
b( p_b )
{};

// ...

};

// alors la ligne devient

const Biniou wesh = Biniou( 5, 'c' );

<--

cette déclaration provoquera avant l'entrée dans le main l'appel au
constructeur que l'on vient de surcharger qui se chargera d'initialiser
l'instance 'wesh'. C'est-à-dire du temps de perdu à initialiser un objet
dont on pouvait connaître par avance le contenu !


Avatar
Gabriel Dos Reis
Guillaume LEMAÎTRE writes:

| Loïc Joly wrote:
| > Guillaume LEMAÎTRE wrote:
| >
| >> La surcharge du constructeur amènerait à une initialisation
| >> dynamique et non statique.
| > Je ne vois pas pourquoi. Peux-tu expliciter ce que tu veux dire ?
| >
|
| à supposer que l'on ait en plus :
|
| -->
|
| class Biniou {
|
| // ...
|
| Biniou( const int p_a, const char p_b ) :
| a( p_a ),
| b( p_b )
| {};
|
| // ...
|
| };
|
| // alors la ligne devient
|
| const Biniou wesh = Biniou( 5, 'c' );
|
| <--
|
| cette déclaration provoquera avant l'entrée dans le main l'appel au
| constructeur que l'on vient de surcharger qui se chargera
| d'initialiser l'instance 'wesh'. C'est-à-dire du temps de perdu à
| initialiser un objet dont on pouvait connaître par avance le contenu !

si tu arrives à mesurer le temps « perdu » à initialiser 'wesh' alors
c'est que ton programme ne fait rien d'intéressant ou il faut que tu
changes de compilateur.

-- Gaby
Avatar
Loïc Joly
Guillaume LEMAÎTRE wrote:

Loïc Joly wrote:

Guillaume LEMAÎTRE wrote:

La surcharge du constructeur amènerait à une initialisation
dynamique et non statique.


Je ne vois pas pourquoi. Peux-tu expliciter ce que tu veux dire ?


à supposer que l'on ait en plus :

-->

class Biniou {

// ...

Biniou( const int p_a, const char p_b ) : a( p_a ), b( p_b ) {};

// ...

};

// alors la ligne devient

const Biniou wesh = Biniou( 5, 'c' );

<--

cette déclaration provoquera avant l'entrée dans le main l'appel au
constructeur que l'on vient de surcharger qui se chargera
d'initialiser l'instance 'wesh'. C'est-à-dire du temps de perdu à
initialiser un objet dont on pouvait connaître par avance le contenu
!


Ah, je crois voir enfin ce que tu entendais par dynamique (j'avais
confondu avec le dynamique de à new ou malloc).

Si c'est bien le cas, je me pose alors quelques questions :

- Est-ce important ? Je n'ai pas l'impression que le temps
d'initialisation de quelques constantes soit en général un problème en
terme de performances.

- Un bon compilateur n'aurait-il pas le droit d'initialiser l'objet wesh
à la compilation ? Voire même de supprimer toute référence à wesh du
programme final et de remplacer tous les wesh.get_a() par 5 (puis de
continuer éventuellement à optimiser). Je n'ai rien vu dans la norme qui
semble empêcher ça (mais si je commence à savoir m'y retrouver pour voir
si quelquechose existe, je suis encore loin de la connaître assez pour
savoir qu'une chose n'existe pas), mais est-ce à la portée des
compilateurs actuels.
En particulier (3.6.2.2) :
An implementation is permitted to perform the initialization of an
object of namespace scope with static storage duration as a static
initialization even if such initialization is not required to be done
statically, provided that
— the dynamic version of the
initialization does not change the value of any other object of
namespace scope with static storage duration prior to its
initialization, and
- the static version of the initialization
produces the same value in the initialized object as would be
produced by the dynamic initialization if all objects not required to
be initialized statically were initialized dynamically.



- Si vraiment c'est important, si la classe Biniou est un aggregate, une
écriture comme celle que tu as écrit au début est possible et t'assure
d'une initialisation pendant la phase statique (8.5.1.14).
When an aggregate with static storage duration is initialized with a
braceenclosed initializerlist, if all the member initializer
expressions are constant expressions, and the aggregate is a POD
type, the initialization shall be done during the static phase of
initialization (3.6.2); otherwise, it is unspecified whether the
initialization of members with constant expressions takes place
during the static phase or during the dynamic phase of
initialization.



--
Loïc



Avatar
Guillaume LEMAÎTRE
Loïc Joly wrote:

Ah, je crois voir enfin ce que tu entendais par dynamique (j'avais
confondu avec le dynamique de à new ou malloc).

Si c'est bien le cas, je me pose alors quelques questions :

- Est-ce important ? Je n'ai pas l'impression que le temps
d'initialisation de quelques constantes soit en général un problème en
terme de performances.



C'est important. Je ne parle pas ici d'un court programme développé par
une unique personne, mais d'un programme de taille industrielle (avec
tous les défauts que ça amène :) ) et surtout dont le temps
d'initialisation est contraint.

On peut supposer que sur les téléphones portables par exemple, il y ait
une contrainte de temps entre le moment où le téléphone est allumé d'un
point de vue purement électrique et le moment où celui-ci vous demande
votre code. Il faut bien voir alors que dans ce temps imparti doivent
être initialisées les constantes globales et que les traitements amenant
à l'appel de verifier_code_acces() doivent être exécutés. Cette
contrainte est fixée par le client et est contractuelle. Donc en tant
que développeur on peut toujours dire "ha non mais c'es tplus long, mais
c'est pas grave", le client s'en fiche, tout ce qu'il voit, c'est que
son nouveau téléphone qui doit être lancé sur le marché met un quart
d'heure à s'initialiser (je caricature, mais peut-être comme ça Gabriel
comprendra :) )

Donc, ce caractère de temps d'initialisation que je sous-estimais
moi-même avant de savoir qu'il peut y avoir des contraintes dessus, est
un vrai problème, de plus difficilement adressable en C++ (alors qu'il
ne le serait pas en C). Pour moi c'est une des lacunes du C++.

- Un bon compilateur n'aurait-il pas le droit d'initialiser l'objet wesh
à la compilation ? Voire même de supprimer toute référence à wesh du
programme final et de remplacer tous les wesh.get_a() par 5 (puis de
continuer éventuellement à optimiser). Je n'ai rien vu dans la norme qui
semble empêcher ça (mais si je commence à savoir m'y retrouver pour voir
si quelquechose existe, je suis encore loin de la connaître assez pour
savoir qu'une chose n'existe pas), mais est-ce à la portée des
compilateurs actuels.
En particulier (3.6.2.2) :

[snip]


Malheureusement, toujours dans le cadre de l'industrie, une fois qu'un
compilateur a été choisi pour un projet, il faut faire avec les moyens
du bord. C'est pour ça que je demandais une technique pas forcément
spécifique à un compilateur ou à un autre, juste un astuce d'écriture à
partir de la grammaire standard C++ amenant à une optimisiation
"suffisamment répandue" :)

En tout cas, merci d'avoir pris mon cas en considération !

Guillaume

Avatar
Gabriel Dos Reis
Guillaume LEMAÎTRE writes:

| Donc, ce caractère de temps d'initialisation que je sous-estimais
| moi-même avant de savoir qu'il peut y avoir des contraintes dessus,
| est un vrai problème, de plus difficilement adressable en C++ (alors
| qu'il ne le serait pas en C). Pour moi c'est une des lacunes du C++.

Cela n'a pas de sens.

Si tu peux l'éviter en C, alors tu peux l'éviter en C++. Où la lacune ?

Ce n'est pas parce que tu /peux/ faire quelque chose que tu dois le faire.

-- Gaby
Avatar
Loïc Joly
Guillaume LEMAÎTRE wrote:


En tout cas, merci d'avoir pris mon cas en considération !


Euh, tu n'a pas répondu sur ce que tu pensais de faire de ta classe un
aggregate, afin de pouvoir l'initialiser comme en C...

--
Loïc

Avatar
kanze
Guillaume LEMAÎTRE wrote in message
news:<brne5n$ffh$...

J'aimerai savoir s'il existe des stratagèmes pour qu'une instance
constante d'une classe soit directement initialisée dans l'exécutable
et ne nécessite pas l'appel de constructeurs globaux.

Pour faire plus clair :

-->

class Biniou {
int a;
char b;

public :

const int get_a( void ) const { return a; };
const char get_b( void ) const { return b; };

int & set_a( void ) { return a; };
char & set_b( void ) { return b; };
};

// ligne invalide, mais qui veut bien dire ce qu'elle veut dire

const Biniou wesh = { 5, 'c' };

<--


Pourquoi c'est invalide ? Elle a l'air parfaitement valide pour moi.
J'utilise parfois quelque chose du genre :

template< typename T1, typename T2 >
struct pod_pair
{
T1 first ;
T2 second ;
operator std::pair< T1, T2 >()
{
return std::pair< T1, T2 >( first, second ) ;
}
} ;

exprès pour me permettre d'écrire par exemple :

pod_pair< char const*, int > const
initTable[] {
{ "toto", 42 },
{ "titi", 34 },
// ...
} ;
std::map< std::string, int >
map( begin( initTable ), end( initTable ) ) ;

La plupart du temps, le but n'est pas tant d'éviter l'initialisation
dynamique, mais de facilité l'écriture, mais si les deux éléments du
pod_pair sont bien POD eux-même, l'initialisation en est bien statique.

La surcharge du constructeur amènerait à une initialisation dynamique
et non statique.


La définition d'un constructeur par l'utilisateur amènerait bien à une
initialisation dynamique. Donc, n'en définis pas.

Aujourd'hui j'en suis réduit à patcher la section 'data' de
l'exécutable pour réaliser mes initialisations, ce qui est efficace
mais peu propre... Donc si l'un d'entre vous a une idée, elle est la
bienvenue


Pour l'instant, je ne vois pas où est le problème. Une classe serait
initialisée statiquement si son constructeur est trivial, et que les
initialisations sont tous des expressions constantes. Le constructeur
est trivial s'il n'est pas déclaré par le programmeur, et

- la classe n'a pas de fonctions virtuelles ni de classes de base
virtuelle,
- toutes les classes de bases ont des constructeurs triviaux, et
- tous les membres données non-statiques qui ont un type de classe ont
des constructeurs triviaux.

(Note bien que dans mon pod_pair, si j'instancie avec le premier type
std::string à la place de char const*, l'initialisation ne serait plus
statique, mais dynamique.)

PS: les initalisations peuvent être citiques dans le cas de programmes
temps-réel embarqués.


Surtout si ces programmes sont en PROM, n'est-ce pas ?

En général, même dans le cas des programmes sur ordinateur général (PC,
Sun, etc.), l'initialisation statique a l'avantage de ne pas introduire
des dépendences dans l'ordre d'initialisation -- quoiqu'il arrive, je
sais que ma variable « initTable » ci-dessus serait initialisée avant
son utilisation.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
kanze
Gabriel Dos Reis wrote in message
news:...
Guillaume LEMAÎTRE writes:

| Loïc Joly wrote:
| > Guillaume LEMAÎTRE wrote:

| >> La surcharge du constructeur amènerait à une initialisation
| >> dynamique et non statique.
| > Je ne vois pas pourquoi. Peux-tu expliciter ce que tu veux dire ?

| à supposer que l'on ait en plus :

| -->

| class Biniou {

| // ...

| Biniou( const int p_a, const char p_b ) :
| a( p_a ),
| b( p_b )
| {};

| // ...

| };

| // alors la ligne devient

| const Biniou wesh = Biniou( 5, 'c' );

| <--

| cette déclaration provoquera avant l'entrée dans le main l'appel au
| constructeur que l'on vient de surcharger qui se chargera
| d'initialiser l'instance 'wesh'. C'est-à-dire du temps de perdu à
| initialiser un objet dont on pouvait connaître par avance le contenu !

si tu arrives à mesurer le temps « perdu » à initialiser 'wesh' alors
c'est que ton programme ne fait rien d'intéressant ou il faut que tu
changes de compilateur.


En ce qui concerne le temps, je suis d'accord avec toi, mais ça ne veut
pas dire que l'initialisation statique est sans intérêt. Je peux penser
à au moins deux cas où il a des avantages :

- La gestion de l'ordre d'initialisation. Toutes les initialisations
statiques auront lieu avant la première initialisation dynamique. Si
on a donc un objet qui pourrait servir dans des constructeurs des
objets statiques dans d'autres unités de compilation, c'est un
avantage énorme qu'il soit initialisé statiquement.

- Dans un système embarqué, un objet constant initialisé statiquement
peut être mis en PROM. Selon l'architecture du système, ça pourrait
avoir des avantages notables.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

1 2