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

initialisation et double déclaration de données static d'un objet non instancié

119 réponses
Avatar
heinquoi
Bjr,
j'ai un pb de compréhension sur ce code:

class Main
{
public:
static HINSTANCE hInstance;
static HINSTANCE hPrevInstance;
static int nCmdShow;
static int MessageLoop( void );
};

HINSTANCE Main::hInstance = 0; // ici, je devrais avoir une
erreur
HINSTANCE Main::hPrevInstance = 0; // ici, aussi

il y a une double déclaration non ?
Si quelqu'un peut m'éclairer ? Et l'objet n'est meme pas initialisé.
Cordialement
Heinquoi

10 réponses

8 9 10 11 12
Avatar
drkm
writes:

/d@¿;;é*G˜)ìWf


[...]

Je n'ai que de tels symboles dans ton article. Un problème de ta
part, ou de mon newsreader ?

--drkm

Avatar
James Kanze
Gabriel Dos Reis writes:

|> writes:

|> [...]
|> | C'est vrai. Mais quel est la signification « classique »
|> | d'un « storage class specifier » ? Déjà en K&R1, le
|> | mot clé « static » pouvait affecter soit le linkage, soit
|> | la durée de vie, selon qu'il sert à la portée de fichier
|> | ou dans une fonction ; « extern » n'affectait que le
|> | linkage,

|> Comme je l'ai expliqué à plusieurs reprises, mais c'est
|> peut-être perdu dans le vacarme, le fait que « static »
|> modifie le linkage est l'accident que Dennis Ritchie lui même
|> regrette. C'est également cela que les gens qui ont proposéde
|> « déprécier » static ont essayé de corriger. Le reste
|> de la signification de « static » (en C++) cadre avec le
|> concept initial de quand tu l'utilises pour une variable locale.

Je l'entends pour la première fois dans ce thread. Ce qui est
certain, c'est que quand j'ai commencé le C, il y a plus de vingt
ans, c'était déjà la signification la plus courante ; comme
j'ai dit, la plupart des règles de codage de C disait de déclarer
les variables à portée de fichier static, au moins qu'on veut
exprès qu'elles ne le soient pas.

|> | « auto » la durée de vie,

|> « auto » en tant que machin-rage truc-specifer est le dual de
|> static: au lieu d'avoir une seule copie on a une copie à chaque
|> appel.

|> | et « register », quelque chose qui n'avait rien à voir ni
|> | avec l'un ni avec l'autre (sauf dans la mésure que «
|> | register » impliquait « auto »).

|> En C, il disait qu'on ne peut pas adresser la mémoire de l'objet
|> ainsi désigné : tu y vois quelque chose qui n'a rien à
|> avoir avec la classe de stockage toi ?

OK. Dans un sens. Si on accepte de la catégorie de stockage, ça
fait référence à où le compilateur place la variable (ce qui
est, en fait, assez raisonable), on a bien auto == sur la pile, et
register == dans un régistre.

J'avoue que je suis peut-être un peu déformé par le C++ -- une
variable auto, c'est une dont on appelle le constructeur et le
destructeur chaque fois qu'il devient ou cesse d'être visible. C'est
la durée de vie qui prime.

|> | Est-ce que tu pourrais me donner une définition de « storage
|> | class », tel que l'expression sert dans les normes C et C++,
|> | autrement que par une liste exhaustive des mot clés concerné
|> | ?

|> Puisque je ne peux rien supposr sur ce que tu sais, dis-mois ce que
|> tu sais et je te dirai ce que tu veux savoir.

Ce que je sais, c'est quel sont les mots clé qu'on considère
« storage class specifiers » en C et en C++. Ce que je sais, c'est
la sémantique dans la contexte du langage pour chacun d'eux.

Ce que je n'arrive pas à faire, c'est de trouver un filon commun.
Dans la contexte actuelle, s'entende -- d'après l'histoire que tu
m'as raconté, je comprends bien d'où ça ait pu venir. Mais j'ai
du mal à trouver une explication de ce que c'est un storage class
specifier, autre que c'est un de « static, extern, ... » (où en
plus, la liste n'est pas identique en C et en C++).

--
James Kanze
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
James Kanze
Gabriel Dos Reis writes:

|> writes:
|> | Gabriel Dos Reis wrote in message
|> | news:...

|> | > writes:

|> | [...]
|> | > | Rien n'empêchait. Et en fait, beaucoup de vocabulaire a
|> | > | été emprunté du langage OO -- on parle bien
|> | > | d'héritage, des classes dérivées, etc. Stroustrup a
|> | > | décidé de ne pas suivre le nomenclature « membre de
|> | > | classe » / « membre d'instance ». Je ne connais pas
|> | > | la raison derrière cette décision, mais il ne me gène
|> | > | pas outre-mésure. Dans d'autres cas, par exemple quand il a
|> | > | décidé de ne pas utiliser « subclass » et «
|> | > | superclass », il a expliqué pourquoi. Mais pas ici, ou
|> | > | plutôt, je n'ai jamais vu une explication. Peut-être
|> | > | Gaby en connaît une (bien que comme j'ai dit, je ne trouve
|> | > | pas qu'une explication soit nécessaire).

|> | > J'ai bien lu ta phrase entre parenthèses mais je ne comprends
|> | > pas très bien tes deux premières phrases. Comme tu le
|> | > sais,

|> | Ne suppose pas trop en ce qui concerne ce que je sais. Je connais
|> | bien

|> J'ai trouvé plus courtois de penser que quelqu'un qui se vante de
|> commencer à programmer en C++ lorsque j'étais encore dans la
|> brousse s'est renseigné sur son outil et connait un bon bout de
|> son histoire,

Pourquoi. Je connais l'histoire que j'ai vecu, mais je ne sais très
peu de ce qui s'est passé avant. C'est intéressant comme ça,
mais ça ne me semble pas nécessaire. Je ne crois pas qu'une
connaissance de Simula m'aiderait dans le C++ que j'utilise aujourd'hui.
À bien d'égards, même le C++ que j'ai utilisé il y a 10 ans
ne m'aide pas tant que ça.

|> que de croire qu'il fait simplement du vacarme relevant de la
|> vantardise sans fond.

Ou peut-être qu'il trouve qu'il y a des choses plus intéressantes
que le C++ dans la vie, et que dans la mésure que ça ne lui sert
à rien de pratique, il n'en a jamais senti le besoin.

|> | la partie de l'histoire du C++ que j'ai vecu -- à partir de
|> | 1992, grosso modo (mais l'utilisation déjà alors des
|> | compilateurs périmés m'en a exposé un peu de l'histoire
|> | postérieure). En ce qui concerne l'histoire ancienne, avant que
|> | le langage ait réelement commencé à se répandre, je
|> | n'en connais que des brides.

|> J'avais également supposé que quelqu'un qui utilise C++ comme
|> un outil professionnel et qui discute des détails et les concepts
|> de C++ a lu D&E.

Je l'ai acheté quand il a sorti. J'y ai jeté un coup d'oeil
rapide. J'ai même régardé en détail ce qui concernait
plusieurs points qu'on en discutait à l'époque (« name
hiding », par exemple, que g++ a réfusé à implémenter
pendant longtemps). Mais je n'ai jamais vu la nécessité à en
lire tout en détail.

|> Bien sûr, on peut arguer que c'est une histoire écrite avec
|> des « coloured glasses », mais au moins c'est une source
|> d'information assez fiable -- à défaut d'en avoir d'autres.

Certes. Si on s'intéressait à l'histoire du langage, on aurait
tort à ne pas le lire.

|> | > C++ emprunte directement à C et Simula.

|> | Ça, j'ai effectivement entendu. Mais ne connaissant rien de
|> | Simula, ça ne me donne qu'une moitié de l'ensemble.

|> Je crois qu'un simple google donne beaucoup de réponses dont les
|> premières contiennent des liens que Michel a postés.

Mais pourquoi faire ?

Tu n'as pas l'air de bien comprendre qu'on dit. J'ai dit simplement que
le vocabulaire de C++ est tel qu'il est, que je ne savais pas pourquoi,
mais que ça ne me genait pas comme ça. Si j'y avais trouvé un
problème, j'aurais pu me poser la question, d'où il a tiré
ça ou ça. Mais dans la mésure où il me convient, tout en
sachant que ce n'est pas le seul vocabulaire possible, ça me suffit.

--
James Kanze
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
Gabriel Dos Reis
James Kanze writes:

[...]

| |> que de croire qu'il fait simplement du vacarme relevant de la
| |> vantardise sans fond.
|
| Ou peut-être qu'il trouve qu'il y a des choses plus intéressantes
| que le C++ dans la vie,

C'est pour cela qu'il en parle autant ;-/

[...]

|
| |> | Ça, j'ai effectivement entendu. Mais ne connaissant rien de
| |> | Simula, ça ne me donne qu'une moitié de l'ensemble.
|
| |> Je crois qu'un simple google donne beaucoup de réponses dont les
| |> premières contiennent des liens que Michel a postés.
|
| Mais pourquoi faire ?
|
| Tu n'as pas l'air de bien comprendre qu'on dit.

Au contraire.

-- Gaby
Avatar
Gabriel Dos Reis
James Kanze writes:

[...]

| |> | « auto » la durée de vie,
|
| |> « auto » en tant que machin-rage truc-specifer est le dual de
| |> static: au lieu d'avoir une seule copie on a une copie à chaque
| |> appel.
|
| |> | et « register », quelque chose qui n'avait rien à voir ni
| |> | avec l'un ni avec l'autre (sauf dans la mésure que «
| |> | register » impliquait « auto »).
|
| |> En C, il disait qu'on ne peut pas adresser la mémoire de l'objet
| |> ainsi désigné : tu y vois quelque chose qui n'a rien à
| |> avoir avec la classe de stockage toi ?
|
| OK. Dans un sens. Si on accepte de la catégorie de stockage, ça
| fait référence à où le compilateur place la variable (ce qui
| est, en fait, assez raisonable), on a bien auto == sur la pile, et
| register == dans un régistre.
|
| J'avoue que je suis peut-être un peu déformé par le C++ -- une
| variable auto, c'est une dont on appelle le constructeur et le
| destructeur chaque fois qu'il devient ou cesse d'être visible. C'est
| la durée de vie qui prime.

Si la mémoire de l'objet est instancié à chaque fois que la
fonction est instanciée, il faut bien appeler le constructeur pour
construire l'objet. En d'autres termes, je dirais que je confonds les
symptomes avec la maladie.

| |> | Est-ce que tu pourrais me donner une définition de « storage
| |> | class », tel que l'expression sert dans les normes C et C++,
| |> | autrement que par une liste exhaustive des mot clés concerné
| |> | ?
|
| |> Puisque je ne peux rien supposr sur ce que tu sais, dis-mois ce que
| |> tu sais et je te dirai ce que tu veux savoir.
|
| Ce que je sais, c'est quel sont les mots clé qu'on considère
| « storage class specifiers » en C et en C++. Ce que je sais, c'est
| la sémantique dans la contexte du langage pour chacun d'eux.

Oui et le langage est une évolution, il a une histoire. Je dirais que
celui qui ignore ou veut ignorer son histoire court le risque d'en
avoir qu'un connaissance scolaire. Cette connaissance scolaire peut
suffire dans certains cas, mais je doute fortement qu'elle aide à
expliquer ou enseigner le langage.

| Ce que je n'arrive pas à faire, c'est de trouver un filon commun.

Regarde dans l'histoire.

En fait, il y a beaucoup de choses comme ça. J'ai déjà vu des gens
faire la confusion et assener, par exemple, que la recherche des noms
å deux phases est le fruit des namespace -- alors qu'en réalité ces
choses étaient considérées bien avant que les namespaces ne soient
inventés.

| Dans la contexte actuelle, s'entende -- d'après l'histoire que tu
| m'as raconté, je comprends bien d'où ça ait pu venir. Mais j'ai
| du mal à trouver une explication de ce que c'est un storage class
| specifier, autre que c'est un de « static, extern, ... » (où en
| plus, la liste n'est pas identique en C et en C++).

Et l'une de reproches qu'un certain nombre d' « anciens » font à la
norme actuelle, c'est qu'elle est rédigée comme une série de longues
listes de cas spéciaux. Certaines personnes ne semblent pas apprécier
les règles simples. Il n'y a pas de perspectives. Oui, c'est un
document technique, mais cela ne veut pas dire qu'il ne doit pas y
avoir de perspective.
Pendant que certaines personnes s'acharnaient à
donner à static, son seul sens qu'il aurait dû avoir, d'autres
personnes ont trouvé l'opportunité de faire en sorte qu'il n'affecte
plus seulement le linkage mais aussi name lookup (un point que peu de
gens savent savoir en ce moment, jusqu'au moment où le compilateur
n'accepte plus le code).

-- Gaby
Avatar
drkm
Gabriel Dos Reis writes:

Pendant que certaines personnes s'acharnaient à
donner à static, son seul sens qu'il aurait dû avoir, d'autres
personnes ont trouvé l'opportunité de faire en sorte qu'il n'affecte
plus seulement le linkage mais aussi name lookup


Tiens. Peux-tu expliquer un peu plus où et comment il intervient
dans le name lookup, stp ?

--drkm

Avatar
drkm
drkm writes:

Gabriel Dos Reis writes:

Pendant que certaines personnes s'acharnaient à
donner à static, son seul sens qu'il aurait dû avoir, d'autres
personnes ont trouvé l'opportunité de faire en sorte qu'il n'affecte
plus seulement le linkage mais aussi name lookup


Tiens. Peux-tu expliquer un peu plus où et comment il intervient
dans le name lookup, stp ?


En fait, tout ce que j'ai trouvé à ce sujet est 3.4.1/12, qui dit
que le nom d'une variable membre statique est recherché de la même
manière que le nom d'une fonction membre. Mais je n'arrive pas à
trouver les différences exactes entre la recherche de nom de variables
membres et celle de fonctions membres.

Ce cherchant, je suis tombé sur 9.4.2/6, qui dit « A local class
shall not have static data members ». Qu'est-ce qu'une « local
class » ? Je dirais une classe locale à une fonction, et je peux
entrevoir les raisons poussant à interdir les variables membres
statiques dans de telles classes [*], mais j'aimerais être sûr.

[*] Par exemple le fait qu'une fonction peut être appelée
plusieurs fois simultanément (récursion), auquel cas, faut-il
avoir une instance du membre statique pour l'entiéreté de ces
classes, ou une par appel de fonction (ce qui ne colle plus
avec « une instance dans tout le programme ») ?

--drkm


Avatar
Gabriel Dos Reis
drkm writes:

| Gabriel Dos Reis writes:
|
| > Pendant que certaines personnes s'acharnaient à
| > donner à static, son seul sens qu'il aurait dû avoir, d'autres
| > personnes ont trouvé l'opportunité de faire en sorte qu'il n'affecte
| > plus seulement le linkage mais aussi name lookup
|
| Tiens. Peux-tu expliquer un peu plus où et comment il intervient
| dans le name lookup, stp ?

Cela arrive dans la seconde phase de résolution des noms pendant
l'instantiation des templates.

Rappelons que la résolution des noms dans les définitions de
template se fait en deux phases: la première phase lie les
utilisations des noms à leurs déclarations dans le contexte de
définition du template ; et la seconde phase résoud les noms
dépendants. En particulier « Argument dependent name lookup » est
utilisée pour les fonctions -- si la syntaxe a la bonne forme.
Exemple:


// sum.h
template<class T>
T sum(T* data, int n) {
T r = T();
while (n--)
r = add(r, data[n]); // add() est dépendant
return r;
}

Le binding de add() dans sum<> sera effectué uniquement pendant
l'instantiation de sum<>. Et comme il a la forme d'un appel de
fonction, en plus avec la « bonne » forme syntaxique ADL sera utilisé
pour le trouver. E.g.

// foo.C
#include "sum.h"
namespace N {
struct foo {
// ...
};

foo add(foo, foo) { ... } // #1
}


int main()
{
N::foo foos[930];
N::foo s = sum(foos, 903); // #2
}


Dans #2, l'instantiation de sum<> va trouver le add() en ligne #1.

Cependant, si comme certains semblent l'adopter en règle, le add dans
N:: a été déclaré static parce qu'elle ne sert que dans foo.C, même si
elle est trouvée par ADL, la seconde phase de résolution des noms va
l'ignorer, parce qu'elle a un linkage interne. Ce qui provoquera une
erreur -- même si la add() se trouve dans la même unité de traduction
que son utilisation.

Certains compilateurs contiennent des bugs et vont accepter le code
(GCC-3.4.0 en fait partie). D'autres comme como vont le rejeter,
selon la norme.

-- Gaby
Avatar
Gabriel Dos Reis
drkm writes:

| drkm writes:
|
| > Gabriel Dos Reis writes:
|
| > > Pendant que certaines personnes s'acharnaient à
| > > donner à static, son seul sens qu'il aurait dû avoir, d'autres
| > > personnes ont trouvé l'opportunité de faire en sorte qu'il n'affecte
| > > plus seulement le linkage mais aussi name lookup
|
| > Tiens. Peux-tu expliquer un peu plus où et comment il intervient
| > dans le name lookup, stp ?
|
| En fait, tout ce que j'ai trouvé à ce sujet est 3.4.1/12, qui dit
| que le nom d'une variable membre statique est recherché de la même
| manière que le nom d'une fonction membre. Mais je n'arrive pas à
| trouver les différences exactes entre la recherche de nom de variables
| membres et celle de fonctions membres.

Regarde 14.6.4.2/1

For a function call that depends on a template parameter, if the
function name is an unqualified-id but not a template-id, the
candidate functions are found using the usual lookup rules (3.4.1,
3.4.2) except that:
--- For the part of the lookup using unqualified name lookup
(3.4.1), only function declarations with external linkage from
the template definition context are found.

--- For the part of the lookup using associated namespaces (3.4.2),
only function declarations with external linkage found in either
the template definition context or the template instantiation
context are found.

If the call would be ill-formed or would find a better match had the
lookup within the associated namespaces considered all the function
declarations with external linkage introduced in those namespaces in
all translation units, not just considering those declarations found
in the template definition and template instantiation contexts, then
the program has undefined behavior.


| Ce cherchant, je suis tombé sur 9.4.2/6, qui dit « A local class
| shall not have static data members ». Qu'est-ce qu'une « local
| class » ?

C'est défini au 9.8/1. C'est une classe déclarée dans le corps
d'une fonction ou impriquée dans une classe locale.

| Je dirais une classe locale à une fonction, et je peux
| entrevoir les raisons poussant à interdir les variables membres
| statiques dans de telles classes [*], mais j'aimerais être sûr.
|
| [*] Par exemple le fait qu'une fonction peut être appelée
| plusieurs fois simultanément (récursion), auquel cas, faut-il
| avoir une instance du membre statique pour l'entiéreté de ces
| classes, ou une par appel de fonction (ce qui ne colle plus
| avec « une instance dans tout le programme ») ?

Une définition d'une classe locale n'est pas « instanciée » à chaque
appel de la fonction -- ce qui soulèverait la même question dont tu
parles -- donc, je ne pense pas que cette question se pose ou que ce
soit la raison pour laquelle c'est interdit. Une membre statique
« appartient » à sa classe, donc devrait subir un sort similaire à sa
classe.

Je n'ai pas mon ARM sous la main pour vérifier, mais il me semble que
cette règle a été ajoutée sur le tard, je ne sais pour quelle raison
-- bien que je puisse avancer des possibles explications.

Mais je suppose que ce que tu peux faire avec une donnée membre
statique d'une classe locale, tu pourrais le faire en déclarant la
variable statique dans la fonction englobante...

-- Gaby
Avatar
James Kanze
Gabriel Dos Reis writes:

[...]
|> | Je dirais une classe locale à une fonction, et je peux
|> | entrevoir les raisons poussant à interdir les variables membres
|> | statiques dans de telles classes [*], mais j'aimerais être
|> | sûr.

|> | [*] Par exemple le fait qu'une fonction peut être appelée
|> | plusieurs fois simultanément (récursion), auquel cas, faut-il
|> | avoir une instance du membre statique pour l'entiéreté de ces
|> | classes, ou une par appel de fonction (ce qui ne colle plus
|> | avec « une instance dans tout le programme ») ?

|> Une définition d'une classe locale n'est pas « instanciée » à chaque
|> appel de la fonction -- ce qui soulèverait la même question dont tu
|> parles -- donc, je ne pense pas que cette question se pose ou que ce
|> soit la raison pour laquelle c'est interdit. Une membre statique
|> « appartient » à sa classe, donc devrait subir un sort similaire à sa
|> classe.

Je croyais plus simplement : il faut définir une variable statique en
dehors de la classe. Or, dans une classe locale, il faut définir tout
dans la classe ; il n'y a pas de syntaxe qui permet une définition en
dehors de la classe.

--
James Kanze
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
8 9 10 11 12