Newsgroup: it.comp.lang.c++
Titolo: Inizializzazione di un vector statico

Ciao,
ho un problema riguardo il codice eseguito prima del "main".
Questo ï¿œ un programma C++ minimale che esemplifica il problema:
 
#include <vector>
#include <iostream>
template <class T>
struct C { static std::vector<T> data; };
template <class T> std::vector<T> C<T>::data;
bool show() { std::cout << C<int>::data.size(); return true; }
bool add_data() { C<int>::data.push_back(7); return true; }
static bool init = add_data();
static bool a1 = show();
int main() { bool a2 = show(); }
 
Spiego il programma.
Definisco il template di classe "C", parametrizzato dal tipo "T",
e contenente solo il vector statico "data".
Poi definisco le due funzioni globali "show" e "add_data",
entrambe le quali istanziano il template di classe "C" per
il tipo "int".
Poi definisco le due variabili globali statiche "init" e "a1",
inizializzate da tali funzioni.
Infine definisco la funzione "main", che chiama ancora la funzione
"show" per stampare la lunghezza del vector.
Il mio problema ï¿œ che se compilo ed eseguo questo programma
usando il compilatore Microsoft Visual C++, ottengo in output "10",
mentre se uso il compilatore GCC ottengo "11".
Ossia il Visual C++ dapprima mostra che il vector "data"
contiene una voce, e poi che non ne contiene, mentre il GCC
mostra che in entrambi gli istanti il vector "data"
contiene una voce.
 
Prima che inizi l'esecuzione della routine "main", tre oggetti
dovrebbero essere inizializzati: "C<int>::data", "init", e "a1".
Ma in quale ordine?
Naturalmente "init" viene inizializzato prima di "a1",
ma quando viene inizializzato "data"?
Pare che GCC lo inizializzi prima di inizializzare "init",
mentre Visual C++ lo inizializzi sia all'inizio che appena
dopo aver inizializzato "a1".
Chiedo: Che cosa ne dice lo standard C++?
Come posso ottenere lo stesso comportamento del GCC
pur usando Visual C++, cioï¿œ come posso evitare di eliminare
dal vector statico le voci che ho appena aggiunto
nel codice di inizializzazione?
Grazie.
 
-- 
 
Carlo Milanesi
http://carlomilanesi.wordpress.com/
 

 nel codice di inizializzazione?
 
Considerando una singola TU, mi pare che lo standard dica che i dati membro 
statici di una classe template debbano essere inizializzati nell'ordine in cui 
sono istanziate le specializzazioni della classe template nei contesti che 
richiedono la definizione dei dati membro statici.
 
Nel tuo caso, l'unica specializzazione C<int> è istanziata prima in show() e 
poi in add_data() ed entrambe richiedono la definizione di C<int>::data. 
Inoltre, entrambi i punti di istanziazione compaiono prima delle definizioni 
di init e a1.
 
Credo quindi che l'ordine di inizializzazione corretto sia rispettivamente 
C<int>::data, init e a1. L'inizializzazione di C<int>::data deve avvenire una 
sola volta. Pare quindi che GCC dia risultati corretti mentre Visual C++ no.
 
Prova a vedere se istanziando esplicitamente C<int>::data in questo modo 
"freghi" Visual C++:
 
template <class T> struct C { static std::vector<T> data; };
template <class T> std::vector<T> C<T>::data;
template std::vector<int> C<int>::data;
// ...
 


 
 
Sembra che VC++ consideri due istanze statiche differenti dell' array
Per risolvere il problema spezza in tre parti le definizione
Nell' header metti la classe,nel header_body la definizione dell' array 
statico  e nel terzo l'istanziazione del template,cosi funziona 
prendendo cosi solo una istanza (provato in VC++ express 2012)
 

 ho un problema riguardo il codice eseguito prima del "main".
...
 
Ho scoperto che il compilatore Visual C++ funziona correttamente se si 
attiva l'opzione di ottimizzazione.
Sembra quindi un bug del compilatore Microsoft in modalitï¿œ debug.
Comunque ho risolto adottando un'altra strategia che evita il problema.
 
--
Carlo Milanesi
 
 
 
 
 
 


 
 
Quale se si puo sapere ?

 Comunque ho risolto adottando un'altra strategia che evita il problema.
 
Cambiare compilatore? :)
 


avendo a che fare con g++,clang++ e vc++ posso affermare che hai proprio 
ragione
 

 Quale se si puo sapere ?
 
Avevo bisogno di creare alcune lookup table analoghe, ma distinte solo 
per tre tipi. Quindi ho creato un template con tre parametri che 
istanzia una lookup table diversa per ogni terna di tipi. E questa 
soluzione aveva il malfunzionamento.
Poi mi sono reso conto che comunque l'insieme delle chiavi di ricerca 
era disgiunto tra le varie terne di tipi. Quindi ho potuto creare una 
lookup table unica. E dato che il difetto si ha solo con un template di 
classe, non con una classe, così funziona.
 
Continuo a usare il compilatore Visual C++ perché sto creando una 
libreria che desidero funzioni con il maggior numero possibile di 
compilatori.



 
 
Se deve essere portabile compila anche con gcc e clang sotto 
linux,potresti avere delle belle sorprese
 
Se invece e' solo sotto windows mi pongo la domanda ' quali altri 
compilatori' ?
 
Lo so che ne esistono altri, ma chi li usa ?
 
 


 
In questo caso non bisogna fare altro che attenersi allo Standard.
A questo scopo, compilatori come GCC forniscono warning efficaci
(previa abilitazione con opportuni flag) sull'uso di codice non portabile.
 
-- 
Vincenzo Mercuri


Infatti, uso sia il compilatore Visual C++ che il compilatore GCC per 
Windows, cercando di attenermi allo standard e usando i flag di 
compilazione più stringenti.
Comunque, se qualcuno vuole fare da beta tester, si faccia avanti.
