OVH Cloud OVH Cloud

[debutant] tableau static const

10 réponses
Avatar
pasde.bcausse.spam
bonsoir,

je declare un tableau static const tab[x];

comment le remplire? (ce sont des valeurs calculées)

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

10 réponses

Avatar
Fabien LE LEZ
On Wed, 18 May 2005 21:57:04 +0200, Bruno Causse :

je declare un tableau static const tab[x];


M'étonnerait... Les tableaux à la C doivent avoir une taille connue à
la compilation.
De plus, comme ton tableau est constant, tu n'es pas censé modifier
les données (i.e. tu ne peux pas le remplir)[*].
En prime, les données en question n'ont pas de type !

En fait, tu peux faire un truc comme

static int const tab[]= { 3, 7, 42, 4654, 12, 132 };

Pour la plupart des autres cas, utilise std::vector<>.
Ainsi, si tu veux calculer à l'exécution les valeurs contenues :

std::vector<int> tab;

for (int i=0; i<12; ++i)
{
tab.push_back (42*i+22);
}





[*] Bon, en fait, je ne suis pas sûr que les données contenues soient
réellement constantes, à cause d'une subtilité du C++ qui m'échappe un
peu, mais c'est le principe...

--
Le grand site de la philosophie animale : <http://perso.edulang.com/philo/>

Avatar
pasde.bcausse.spam
Fabien LE LEZ wrote:

On Wed, 18 May 2005 21:57:04 +0200, Bruno Causse :

je declare un tableau static const tab[x];


M'étonnerait... Les tableaux à la C doivent avoir une taille connue à
la compilation.


oui, un peu rapide :-)

ex: static const int tab[42];

De plus, comme ton tableau est constant, tu n'es pas censé modifier
les données (i.e. tu ne peux pas le remplir)[*].


voila mon probleme :(

donc il n'est pas possible d'avoir un tableau de constantes aleatoires
par exemple;

En prime, les données en question n'ont pas de type !

desolé :-)


En fait, tu peux faire un truc comme

static int const tab[]= { 3, 7, 42, 4654, 12, 132 };



oui mais je ne connais pas les valeurs.

Pour la plupart des autres cas, utilise std::vector<>.
Ainsi, si tu veux calculer à l'exécution les valeurs contenues :

std::vector<int> tab;

for (int i=0; i<12; ++i)
{
tab.push_back (42*i+22);
}



un vector a les memes perfs qu'un tableau ? les données peuvent etre
constantes?


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


Avatar
Richard Delorme
bonsoir,

je declare un tableau static const tab[x];

comment le remplire? (ce sont des valeurs calculées)


Deux solutions :
1) en ne le déclarant pas const.
2) en utilisant un (méta-)programme qui va créer un fichier où est
défini tab[] avec les bonnes valeurs d'initialisations.

--
Richard

Avatar
Fabien LE LEZ
On Wed, 18 May 2005 22:29:25 +0200,
(Bruno Causse):

static int const tab[]= { 3, 7, 42, 4654, 12, 132 };


oui mais je ne connais pas les valeurs.


Dans ce cas tu n'as pas besoin d'un tableau à la C.

un vector a les memes perfs qu'un tableau ?


C'est une évidence : le type canonique en C++ pour avoir un tableau
est std::vector<>. On n'utilise généralement les autres formes
(std::list<>, tableaux à la C, etc.), que si on a une bonne raison de
ne pas utiliser std::vector<>. Donc, ta question revient à
"std::vector<> a les mêmes performances que std::vector<>"...

Pour ne pas répondre à ta question : dans la quasi-totalité des cas,
on ne se pose pas la question des performances. Si une fonction
appelée une seule fois dans le programme s'exécute en 10 ns au lieu de
1 ns, c'est pas bien grave.

Pour répondre à ta question : l'accès à un élément de std::vector<>
est aussi rapide que l'accès à un élément d'un tableau à la C.

les données peuvent etre constantes?


Oui, il suffit de déclarer const ton std::vector<>. Sauf que bien sûr,
tu ne peux pas le modifier, donc pas le remplir non plus.

Exemple pratique :

void f (std::vector<int> const& v)
{
// Ici, on peut lire v, mais pas le modifier
}

void g()
{
std::vector<int> v; // Non constant, on peut le modifier
v.push_back (3); // D'ailleurs, on le modifie
f (v); /* f, par contre, s'engage, par son prototype, à ne pas le
modifier */
}

--
Le grand site de la philosophie animale : <http://perso.edulang.com/philo/>


Avatar
pasde.bcausse.spam
Richard Delorme wrote:

bonsoir,

je declare un tableau static const tab[x];

comment le remplire? (ce sont des valeurs calculées)


Deux solutions :
1) en ne le déclarant pas const.


validé, mais peu satisfaisant.

2) en utilisant un (méta-)programme qui va créer un fichier où est
défini tab[] avec les bonnes valeurs d'initialisations.


quoi un char d'assaut? :-)


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


Avatar
Vincent Lascaux
"Bruno Causse" a écrit dans le message de
news: 1gws1yu.neeml810gq6csN%
bonsoir,

je declare un tableau static const tab[x];

comment le remplire? (ce sont des valeurs calculées)


Ca fait peut être un peu char d'assaut aussi...

struct MonTableauInitialise
{
int data[x];
MonTableauInitialise()
{
//Initialisation
}
};
static const MonTableauInitialise tab;

Ensuite l'acces se fait par tab.data (ou alors en surchargeant l'opérateur
[]).


J'ai peur de dire une bêtise parceque je sais qu'il faut rarement (jamais ?)
dériver des classes de la STL, mais est ce qu'on est pas dans un cas
"contre-exemple" :

struct MonTableauInitialise : public std::vector<int>
{
MonTableauInitialise()
: std::vector<int>(std::vector<int>::size_type(x), 0)
{
//Initialisation
}
}
static const MonTableauInitialise tab;

Ici l'acces se fait comme à un vecteur constant (c'est à dire tab[],
tab.begin() et toutes les bonnes propriétés)

--
Vincent

Avatar
Fabien LE LEZ
On Wed, 18 May 2005 23:41:58 +0200, "Vincent Lascaux"
:

J'ai peur de dire une bêtise parceque je sais qu'il faut rarement (jamais ?)
dériver des classes de la STL,


Effectivement.

class Catastrophe: public std::vector<int>
{ ... };

std::vector<int>* ptr= new Catastrophe;
delete ptr; // Comportement indéfini par le destructeur de
std::vector<> n'est pas virtuel.

mais est ce qu'on est pas dans un cas "contre-exemple" :

struct MonTableauInitialise : public std::vector<int>
{
MonTableauInitialise()
: std::vector<int>(std::vector<int>::size_type(x), 0)
{
//Initialisation
}
}
static const MonTableauInitialise tab;


En fait, ça pourrait effectivement être un contre-exemple si le
constructeur était privé (en gros, ça donnerait un singleton).

Mais en pratique, il est rare d'avoir un réel besoin de dériver
directement d'un conteneur.
En effet, ce tableau, est-il réellement tout seul, sans autres données
connexes à mettre dans le même objet ? Et si c'est le cas
actuellement, le sera-ce toujours ?

Note que je parle d'expérience : il m'est arrivé de braver les
interdits et de dériver d'un conteneur ; à chaque fois, j'ai fini par
abandonner l'idée, parce que ma classe devenait plus complexe, et
l'héritage ne correspondait plus à rien.


--
Le grand site de la philosophie animale : <http://perso.edulang.com/philo/>

Avatar
kanze
Bruno Causse wrote:
Fabien LE LEZ wrote:

On Wed, 18 May 2005 21:57:04 +0200, Bruno Causse :

je declare un tableau static const tab[x];


M'étonnerait... Les tableaux à la C doivent avoir une taille
connue à


la compilation.


oui, un peu rapide :-)

ex: static const int tab[42];

De plus, comme ton tableau est constant, tu n'es pas censé
modifier les données (i.e. tu ne peux pas le remplir)[*].


voila mon probleme :(

donc il n'est pas possible d'avoir un tableau de constantes
aleatoires par exemple;


Bien sûr que si. La dimension doit être constante, mais les
valeurs d'initialisation peuvent être des expressions
quelconques, par exemple :

static int const tab[] =
{ (srand( time( NULL ) ), rand()), rand(), rand(), rand() } ;


En prime, les données en question n'ont pas de type !


desolé :-)

En fait, tu peux faire un truc comme

static int const tab[]= { 3, 7, 42, 4654, 12, 132 };


oui mais je ne connais pas les valeurs.


Il a donné un exemple. Mais les expressions peuvent être
dynamiques.

Dans le cas des initialisations dynamiques, il faut bien faire
attention à l'ordre d'initialisation. (AMHA, une des raisons
principales d'utiliser un tableau de type C, plutôt qu'un
std::vector, c'est qu'il permet une initialisation statique, qui
évite donc tous les problèmes d'ordre d'initialisation.)

Pour la plupart des autres cas, utilise std::vector<>.
Ainsi, si tu veux calculer à l'exécution les valeurs
contenues :

std::vector<int> tab;

for (int i=0; i<12; ++i)
{
tab.push_back (42*i+22);
}


un vector a les memes perfs qu'un tableau ?


Ça dépend de l'implémentation. Et ce qu'on en fait --
typiquement, la création d'un vector est nettement moins rapide
que celle d'un tableau de type C, mais il ne doit pas y avoir
une grande différence lors des accès. Dans l'ensemble, si tu as
une petite classe, du genre :

class Point
{
std::vector< double > loc ; // Toujours trois éléments
// ...
} ;

et tu en crées des millions, la différence en performance par
rapport à double[ 3 ] risque d'être importante. Mais la plupart
du temps, ce n'est pas une motivation. Le profiler te dira.

La plupart du temps, quand on utilise les tableaux de type C,
c'est pour éviter des problèmes de l'ordre d'initialisation, ou
pour exploiter la syntaxe d'initialisation, quand même plus
simple à écrire et à comprendre que celle d'un std::vector.

les données peuvent etre constantes?


Si le std::vector est const, les données sont const. Le
problème, c'est l'initialisation. Dans la pratique, à peu près
la seule initialisation intéressante pour un std::vector const,
c'est celui à deux itérateurs :
std::vector< int > const myValues( init.begin(), init.end() ) ;
Mais ça ne fait que répousser le problème ; on finit avec
quelque chose comme :
static int const init[] = { 1, 1, 2, 3, 5 } ;
std::vector< int > const v( init, init + 5 ) ;
et alors, pourquoi le std::vector ?

Note que ce genre de chose est bien intéressant si on a un
std::set ou un std::map. J'ai beaucoup de code du genre :

typedef std::map< std::string, MyClass > Map ;
struct MapInit
{
char const* key ;
int a ;
int b ;
operator Map::value_type() const
{
return Map::value_type(
std::string( key ),
MyClass( a, b ) ) ;
}
} ;
MapInit const init[] =
{
{ "a1b1", 1, 1 },
{ "a2b5", 2, 5 },
// ...
}
Map const map( begin( init ), end( init ) ) ;

Strictement parlant, j'aurais pû me passer aussi de map, et fait
une récherche linéaire sur init (au moyen de std::find,
évidemment). Mais l'utilisation de std::map est plus intuitive,
une fois le map construit, même si c'est parfois un peu moins
vite, parce que je n'hésite pas à m'en servir, même quand le map
ne contient que trois ou quatre éléments -- à partir d'une
dizaine d'éléments, std::map devient nettement plus rapide, et à
partir d'une centaine de millier (ce qui suppose une génération
automatique du tableau d'initialisation), si les performances
sont critiques, il faut remplacer std::map par un tableau haché.

--
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
Bruno CAUSSE
dans l'article ,
à a écrit le 19/05/05 9:49 :

Merci pour ta patience :-)

un vector a les memes perfs qu'un tableau ?


Ça dépend de l'implémentation. Et ce qu'on en fait --
typiquement, la création d'un vector est nettement moins rapide
que celle d'un tableau de type C, mais il ne doit pas y avoir
une grande différence lors des accès. Dans l'ensemble, si tu as
une petite classe, du genre :

class Point
{
std::vector< double > loc ; // Toujours trois éléments
// ...
} ;

et tu en crées des millions, la différence en performance par
rapport à double[ 3 ] risque d'être importante. Mais la plupart
du temps, ce n'est pas une motivation. Le profiler te dira.

La plupart du temps, quand on utilise les tableaux de type C,
c'est pour éviter des problèmes de l'ordre d'initialisation, ou
pour exploiter la syntaxe d'initialisation, quand même plus
simple à écrire et à comprendre que celle d'un std::vector.


Faut il utiliser (recommander) vector en lieu et place d'un simple tableau
(dans le cas ou seul l'indexage "cad []" est utilisé)

Remarques : je ne me pose pas la question avec string et char*.

Je poursuis mon apprentissage :-).
[troll]
Il me faudrait la syntaxe java avec les perfs du c++
[troll]

les données peuvent etre constantes?


Si le std::vector est const, les données sont const. Le
problème, c'est l'initialisation. Dans la pratique, à peu près
la seule initialisation intéressante pour un std::vector const,
c'est celui à deux itérateurs :
std::vector< int > const myValues( init.begin(), init.end() ) ;
Mais ça ne fait que répousser le problème ; on finit avec
quelque chose comme :
static int const init[] = { 1, 1, 2, 3, 5 } ;
std::vector< int > const v( init, init + 5 ) ;
et alors, pourquoi le std::vector ?

Note que ce genre de chose est bien intéressant si on a un
std::set ou un std::map. J'ai beaucoup de code du genre :

typedef std::map< std::string, MyClass > Map ;
struct MapInit
{
char const* key ;


Tiens et pourquoi pas la classe string?

int a ;
int b ;
operator Map::value_type() const
{
return Map::value_type(
std::string( key ),
MyClass( a, b ) ) ;
}
} ;
MapInit const init[] > {
{ "a1b1", 1, 1 },
{ "a2b5", 2, 5 },
// ...
}
Map const map( begin( init ), end( init ) ) ;

Strictement parlant, j'aurais pû me passer aussi de map, et fait
une récherche linéaire sur init (au moyen de std::find,
évidemment). Mais l'utilisation de std::map est plus intuitive,
une fois le map construit, même si c'est parfois un peu moins
vite, parce que je n'hésite pas à m'en servir, même quand le map
ne contient que trois ou quatre éléments -- à partir d'une
dizaine d'éléments, std::map devient nettement plus rapide, et à
partir d'une centaine de millier (ce qui suppose une génération
automatique du tableau d'initialisation), si les performances
sont critiques, il faut remplacer std::map par un tableau haché.



On verra ca plus tard,
--
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
kanze
Bruno CAUSSE wrote:
dans l'article
,
à a écrit le 19/05/05
9:49 :

La plupart du temps, quand on utilise les tableaux de type
C, c'est pour éviter des problèmes de l'ordre
d'initialisation, ou pour exploiter la syntaxe
d'initialisation, quand même plus simple à écrire et à
comprendre que celle d'un std::vector.


Faut il utiliser (recommander) vector en lieu et place d'un
simple tableau (dans le cas ou seul l'indexage "cad []" est
utilisé)


En général, je crois que oui. J'utilise std::vector sauf quand
il y a des contre-indications. Donc, par exemple, je veux un
tableau 3x3, initialisé avec 11,12,13,21,22,23,31,32,33. Dans ce
cas-là, j'écrirais bien :

int v[3][3] = { { 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 } } ;

Une initialisation équivalente pour un std::vector (qui serait
déjà un std::vector< std::vector< int > >) serait franchement
pénible.

Remarques : je ne me pose pas la question avec string et
char*.


Il y a effectivement moins de raisons à préférer char*, mais il
reste quand même parfois l'initialisation statique.

[...]
Note que ce genre de chose est bien intéressant si on a un
std::set ou un std::map. J'ai beaucoup de code du genre :

typedef std::map< std::string, MyClass > Map ;
struct MapInit
{
char const* key ;


Tiens et pourquoi pas la classe string?


Parce que je veux une initialisation statique. Un type POD,
quoi. (Encore qu'ici, ce n'est pas trop important.)

C'est l'histoire de l'ordre d'initialisation. Par définition,
une initialisation statique ne peut pas dépendre d'une autre
initialisation, et surtout, les initialisations statiques
s'effectuent avant toutes les autres initialisations. C-à-d que
je peux utiliser un objet initialisé statiquement même dans le
constructeur d'un autre objet statique, sans inquiètude.

(Ici, je ne m'en suis servi que tout de suite après, dans la
même unité de compilation. Et à l'intérieur d'une unité de
compilation, l'ordre d'initialisation est garanti être celui des
déclarations. C'était donc pas vraiment nécessaire. Mais c'est
une bonne habitude à prendre : préférer l'initialisation
statique pour des objets statiques, quand ça ne pose pas
d'autres problèmes.)

--
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