Newsgroup: it.comp.lang.c++
Titolo: SemiOT - Variabili statiche, troppo statiche

Ho scoperto di recente (purtroppo) che una variabile dichiarata
statica all'interno del metodo di un oggetto mantiene lo stesso valore
anche se gli oggetti istanziati sono diversi:
MyClass
{
  public:
    void doTest();
}
void MyClass::doTest()
{
  static int testVal = 0;
  testVal++;
  std::cout << "testVal = " << testVal << std::endl;
}
int main()
{
  MyClass *obj1, *obj2;
  obj1 = new MyClass;
  obj2 = new MyClass;
  obj1->doTest();
  obj2->doTest();
  delete obj1;
  delete obj2;
}
Questo stamperà:
testVal = 1
testVal = 2
che è una cosa tremenda, sicuramente corretta ma tremenda.
Il mio problema in realtà non è C++ ma spero di risolvere lo stesso
postando a voi la questione.
In realtà programmo in ObjectiveC ma diciamo che spero che analizzando
la questione in C++ io possa risolvere anche dall'altra parte.
La questione è che ho alcuni metodi che eseguono delle animazioni,
composte da più stadi: uno stadio iniziale in cui viene inizializzato
tutto ciò che serve per animare un oggetto, uno stato successivo in
cui vengono eseguite delle animazioni, ed uno stadio finale in cui
vengono azzerate le variabili usate dal metodo.
Praticamente un metodo è sviluppato più o meno in questo modo:
metodo()
{
  static int locStatus = 0;
  static int iObj;
  Card *theObj;
  switch (locStatus) // locStatus indica che cosa deve fare il metodo
  {
    case 0:
      // Nascondo tutti gli oggetti
      for (iObj=0; iObj < ...; iObj++)
      {
        theObj = [vObjects objectAtIndex:iObj];
        [theObj setVisible:NO];
      }
      // Mi preparo per animare il singoli oggetti
      iObj = 0;
      // Imposto lo stadio successivo
      locStatus++;
      // Faccio in modo che questo metodo venga richiamato fra 0.2
secondi
      // ....
      break;
  case 1:
      // Prendo l'oggetto i-esimo
      theObj = [vObjects objectAtIndex:iObj];
      // Lo animo
      [theObj doSomeStuff];
      // Calcolo l'oggetto successivo
      iObj++;
      if (iObj < [vObjects count]) // se non ho animato tutti gli
oggetti...
      {
        // Faccio dinuovo in modo che questo metodo venga richiamato
fra tot secondi
        // richiamando un temporizzatore
      }
      else // ho finito, era l'ultimo oggetto. Azzero tutto
      {
        iObj = 0;
        locStatus = 0;
      }
      break;
  }
}
Come vedete usando una variabile statica non riempio l'oggetto di
variabili locali che servirebbero solo localmente in ogni metodo, e
che possono aumentare con l'implementazione di nuovi metodi
dell'oggetto.
Però, come dicevo, ho scoperto che le variabili statiche di ogni
metodo sono comuni alla classe e non ai singoli oggetti creati. E
questo crea molti problemi nel momento in cui più istanze vogliono
usare gli stessi metodi contemporaneamente.
Come si potrebbe risolvere?
Grazie e scusate il semi-OT.

 anche se gli oggetti istanziati sono diversi:
Eggià, perché a tutti gli effetti non è una variabile di 
istanza. E' cmq voluto e serve qualora serva una variabile 
shared.
Come potrebbe essere altrimenti ? PEr definizione 
l'istanziazione è un processo di run time, per cui non può 
essere in generale prevedibile, a compile o link time, il 
numero di istanze (che, pure in genere, sarà variabile nel 
tempo). Allora come potrebbe mai il compilatore allocare un 
oggetto "fisso" in quantità variabile ?
Tutto quanto è static è conosciuto a compile time, e viene 
allocato prima ancora di entrare nel punto di ingresso (es. 
main()) e viene liberato solo dopo l'exit point.

Non mi riesce di capire però se devi inizializzare oggetti 
solo in contesto specifico di ciascuna animazione o anche 
oggetti condivisi. Se è una mistura, ovviamente ti 
serviranno variabili di istanza (da inizializzare nei 
costruttori) e static (da inizializzare esplicitamente alla 
dichiarazione, o dopo, tipo alla chiamata del primo 
costruttore ed una sola volta)

in realtà non ho esattamente capito il problema, perché più 
che altro mi pare che il tuo lock sia un blocco al CODICE, 
non tanto un oggetto dati, ma una specie di semaforo per non 
sovrapporre le chiamate (succede se scrivi ad es. interfacce 
asincrone user-driven e agganci gli eventi alle procedure).
Se (SE !) ho capito bene, non vuoi che il codice della 
funzione riparta prima che è finita la esecuzione precedente.
In questo caso il tuo semaforo statico mi pare adatto, in 
quanto anche il codice è shared (unico) ma lo stack frame 
locale garantisce una esecuzione multipla (annidata) in caso 
tu non prenda appunto la garanzia del semaforo.
Per inciso, la tua variabile statica, non è neppure di 
istanza, ma ha uno scope a livello di procedura, ergo ancora 
più limitata. Nessun altro metodo della stessa classe e 
della stessa istanza può vedere quel lock.
Se vuoi quello, devi dichiararlo nella classe, non dentro un 
metodo ... ma se è un semaforo di esecuzione accodata delle 
chiamate multiple allo stesso metodo, va bene lì dove si 
trova ...
Credo di non avere capito bene il problema, in efffetti
ciao
Sorry
Soviet




Il modo migliore per associare dati ad una istanza consiste 
nell'immagazzinarli nell'istanza stessa, ma sembra che tu non lo voglia 
fare - e non ne capisco esattamente il motivo.
In C++, tramite l'ereditarietà multipla, puoi fare in modo che la 
struttura del programma resti chiara e ben definita associando ad ogni 
concetto una classe, per poi combinare i vari concetti in base alle 
esigenze.
Per esempio, puoi creare una classe Animation, che memorizzi lo stato 
dell'animazione ad ogni determinato momento, quindi puoi derivare una 
classe Animatable sia da una classe Object che dalla classe Animation, 
facendo in modo che la classe Object di per sé non contenga informazioni 
che non servono ad altre classi derivate, per esempio:
struct Object {
     int x;
     int y;
};
struct Animation {
     int frame;
};
class Animatable: private Object, private Animation {
public:
     void draw() {
         // usa x, y e frame dalle classi base
         // per disegnare l'animazione al frame corretto
     }
};
Il problema è che non credo tu possa fare lo stesso in ObjectiveC, ma 
non conosco questo linguaggio quindi devi sbrogliartela tu vedendo se 
puoi applicare questi concetti nel tuo contesto.
Un metodo per aggirare il problema (dato che non vuoi aggiungere membri 
alla classe) consiste nel creare dei metodi d'aiuto che immagazzinino le 
informazioni in base ad un ID associato alle varie istanze, per esempio:
int getStatus(int ID) {
     // recupera lo status da un contenitore associativo tramite ID
     return status;
}
void setStatus(int ID, int status) {
     // salva lo status in un contenitore associativo tramite ID
}
Quindi nel tuo metodo:
void draw() {
     // recupera un ID in qualche modo
     int status = getStatus(objectID);
     // usa e modifica status
     setStatus(objectID, status);
}
Per poter funzionare correttamente le funzioni getStatus e setStatus 
devono essere all'interno di un modulo con un contenitore associativo 
statico visibile ad entrambe, oppure devono essere metodi di un'altra 
classe.
Resta il problema che questo approccio potrebbe non essere il migliore 
all'interno degli idiomi dell'ObjectiveC... non c'è nessun gruppo che 
discuta di tale linguaggio?
Va be', spero di esserti stato d'aiuto in qualche modo.
-- 
  FSC - 
http://userscripts.org/scripts/show/59948
 
http://fscode.altervista.org
 - 
http://sardinias.com

La questione è piuttosto semplice, ma non riesco ad esprimerla senza
entrare troppo nel merito dell'ObjectiveC.
Supponiamo di avere un oggetto, uno Sprite, composto da una collezione
di oggetti Sprite.
Immaginiamo ad una sequenza verticale di sferette, l'oggetto finalo lo
chiamo Catena.
Quindi l'oggetto catena è composto da un insieme di sferette.
In realtà l'oggetto ha al suo interno un array di oggetti Sprite,
ognuno dei quali rappresenta una sferetta.
Ora immaginiamo di voler disegnare le sferette sullo schermo in
sequenza.
Non posso ciclare l'array e per ogni sprite eseguire il disegno. Le
sferette comparirebbero contemporaneamente.
E non posso ciclare l'array impostando un'attesa fra il disegno di una
sfera e l'altra: farei crollare le prestazioni.
Quindi se volessi far comparire le sferette in sequenza, devo
ricorrere ad altro.
Questo "altro" è un oggetto globale, un timer a cui posso dire fra
quanto tempo deve richiamare quale metodo di quale oggetto.
Detto ciò, l'idea principale è questa: il metodo "drawBalls" (per
esempio) dell'oggetto deve inizialmente nascondere tutte le sfere, poi
disegnare la prima, invocare n-volte il timer per dire "fra 0.1
secondo richiama il metodo drawBalls", metodo che non deve più
nascondere le sferette ma mostrare l'i-esima.
Dopo aver mostrato l'ultima, il metodo deve prepararsi perchè se viene
chiamato dinuovo deve iniziare da capo: nascondere le sferette e poi
mostrarle una ad una.
Tutto questo a livello teorico, ed a prescindere dal C++.
Su cosa mi basavo?
Sulle variabili statiche.
La logica per creare dei metodi per animazioni complesse era questa:
una variabile locale statica chiamata locStatus indicava in che stadio
si trovava l'animazione.
Ad esempio se lo stadio 0 la funzione è stata _appena_ chiamata,
quindi ad esempio ciclo tutte le sferette e le nascondo.
A quel punto passo a locStatus = 1.
In questo stato vuol dire che la funzione deve disegnare una sferetta.
Prende la sferetta iSferetta, la disegna.
Incrementa la variabile iSferetta e invoca il timer globale dicendogli
"fra 0.1 secondi richiama il metodo drawBalls dell'oggetto this".
Quando il metodo verrà richiamato, la variabile locStatus essendo
statica varrà ancora 1, e lui saprà che dovrà disegnare la sfera
successiva.
Arrivato all'ultima sferetta, il metodo drawBalls invece di invocare
ancora il timer porrà locStatus = 0.
Questo era lo scopo della variabile statica nei miei metodi.
Ogni oggetto può avere più metodi per eseguire animazioni complesse, e
quindi io pensavo che usando variabili locali statiche dentro ogni
metodo non avrei dovuto usare variabili locali dell'oggetto, e avrei
mantenuto tutto più pulito.
Quello che succede però è che se istanzio due oggetti "obj1" ed "obj2"
della stessa classe "Corda", il metodo "drawBalls" di entrambi gli
oggetti usa la stessa variabile statica. Quindi richiamare entrambi i
metodi nello stesso istante crea un putiferio.
Vorrei evitare di inserire queste variabili statiche nell'oggetto per
il semplice fatto che molti oggetti hanno diversi metodi di disegno,
ognuno dei quali esegue animazioni diverse, e quindi semplicemente
riempirei l'oggetto di variabili "inutili" a livello di oggetto in
quanto contavo di usarle solo in quei metodi, ma tutto qui. Non è un
problema in realtà togliere queste dichiarazioni dai metodi e metterle
nell'oggetto stesso.
Quello che chiedevo quindi in linea più generale è: posso fare in modo
che una variabile statica "pippo" dichiarata in un metodo, lavori
separatamente da istanza ad istanza?
In alternativa come posso fare per evitare di dover portare quelle
variabili fuori dai metodi?

 variabili fuori dai metodi?
Tecnicamente impossibile [*]
Devi per forza immagazzinare l'informazione nell'istanza come ho 
mostrato sopra, oppure devi utilizzare un qualche contenitore 
associativo e delle funzioni esterne così come ho mostrato nell'altro post.
Trovato nessun gruppo relativo all'ObjectiveC?
[*] Le funzioni non sono "istanziabili", quindi non puoi differenziare 
una chiamata da un'altra senza fare interagire le funzioni stesse con il 
mondo esterno (o gli passi le informazioni o gli permetti di recuperarle 
in qualche modo, fine dei giochi).


 in qualche modo, fine dei giochi).
E quindi questo vuol dire che no, non posso sfruttare in nessun modo
le variabili statiche.
Il che mi porta a cercare altre strade per ottenere ciò che voglio :)
Grazie per le risposte :)

 Grazie per le risposte :)
Di niente, buona fortuna :-)
