Inizializzazione dati membro statici di una classe [C++]

di il
8 risposte

Inizializzazione dati membro statici di una classe [C++]

Ciao, come da titolo avrei dei dubbi sul quando e dove inizializzare i dati membro statici privati di una classe dichiarata ed utilizzata all'interno di un singolo file .cpp.

Un paio di considerazioni preliminari:

- i dati membro statici sono inizializzati a zero di default, giusto?
- nel mio caso il dato membro statico è un array, il quale ipotizzo necessiti di un'apposita funzione membro statica per la sua inizializzazione;
- la suddetta funzione membro statica addetta alla modifica dell'array deve essere richiamata una sola volta.

Consideriamo quindi il seguente esempio:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>

using namespace std;

class A
{
private:
    int n;
    static int v[10];
    static void set_v();

public:
    A(const int N);
    void fun();
};
int A::v[10];

void A::set_v()
{
    for(unsigned int i = 0; i < 10; v[i++] = rand() % 10 + 1);
}

A::A(const int N)
{
    if(!v[0])
    {
        set_v();
    }
    n = N;
}

void A::fun()
{
    for(unsigned int i = 0; i < 10; ++i)
    {
        cout << (v[i] < n ? to_string(v[i]) : "-") << " ";
    }
    cout << endl;
}

int main()
{
    srand(time(0));
    A a1(6);
    a1.fun();
    A a2(6);
    a2.fun();
}

L'inizializzazione (o forse sarebbe più corretto parlare di assegnazione) del dato membro statico A::v è affidata alla funzione membro statica A::set_v(), ma il problema è quando e dove richiamarla, tenendo anche conto del fatto che deve essere richiamata una sola volta.

L'unica cosa che mi è venuta in mente per risolvere il problema è stata quella di inserire set_v() all'interno del costruttore della classe, e per fare in modo che set_v() venga richiamata una sola volta ho sfruttato l'inizializzazione a zero di default dei dati membro statici.

A funzionare sembra che funzioni, ma mi chiedevo, anche considerando i limiti relative alle mie conoscenze del linguaggio, se esista un modo diverso e “più corretto” per farlo.

8 Risposte

  • Re: Inizializzazione dati membro statici di una classe [C++]

    Vanno sempre inizializzate. 

    Per l'inizializzazione di default puoi chiamare il costruttore di default:

    int A::v[10]{};

    Ovviamente ne puoi definire uno tu qualora si tratti di una classe. 

    Se è una costante, la puoi inizializzare direttamente nella dichiarazione della classe. 

    Se vuoi fare un'assegnazione unica, puoi definire un'apposita variabile bool statica, che verrà impostata a true quando chiami per la prima volta il costruttore di A ovvero quando allocherai il primo oggetto A. Tutte le altre volte il costruttore la controllerà e se sarà true non modificherà più la variabile. 

  • Re: Inizializzazione dati membro statici di una classe [C++]

    Ma nel suo caso  va bene v[0] che non sarà mai più uguale a zero, perché usare un'altra variabile?

    Potresti generare l'array in fase di compilazione coi vari constexpr, ma è un casino perché devi scriverti rand e seed a mano (non si possono usare quelli standard)

  • Re: Inizializzazione dati membro statici di una classe [C++]

    Scusa, ma non riesco a capire come la tua risposta si colleghi alla mia domanda.

    01/06/2023 - Alexv ha scritto:


    Vanno sempre inizializzate. 

    Qual è il soggetto? Le variabili membro statiche?
    Quindi non è vero che quando vengono definite e non inizializzate, sono inizializzate a zero di default?

    01/06/2023 - Alexv ha scritto:


    Per l'inizializzazione di default puoi chiamare il costruttore di default:

    int A::v[10]{};

    Ovviamente ne puoi definire uno tu qualora si tratti di una classe. 

    Non capisco, che c'entra il costruttore con v che è un array membro statico della classe?

    01/06/2023 - Alexv ha scritto:


    Se è una costante, la puoi inizializzare direttamente nella dichiarazione della classe. 

    Come faccio se l'inizializzazione necessita di un ciclo for?

    01/06/2023 - Alexv ha scritto:


    Se vuoi fare un'assegnazione unica, puoi definire un'apposita variabile bool statica, che verrà impostata a true quando chiami per la prima volta il costruttore di A ovvero quando allocherai il primo oggetto A. Tutte le altre volte il costruttore la controllerà e se sarà true non modificherà più la variabile. 

    Ci avevo pensato, ma nel caso in questione ho ritenuto di poterne fare a meno in quanto ho sfruttato la (supposta) inizializzazione a zero di default dei membri statici e il fatto che set_v() fa in modo che v abbia tutti valori positivi.

    Magari potresti mostrarmi come modificheresti il codice da me postato per farmi capire meglio cosa intendi.

  • Re: Inizializzazione dati membro statici di una classe [C++]

    01/06/2023 - Weierstrass ha scritto:


    Ma nel suo caso  va bene v[0] che non sarà mai più uguale a zero, perché usare un'altra variabile?

    Potresti generare l'array in fase di compilazione coi vari constexpr, ma è un casino perché devi scriverti rand e seed a mano (non si possono usare quelli standard)

    Non avevo ancora letto questo messaggio prima di rispondere.

    Quindi relativamente al codice che ho postato è quello il modo corretto di implementare ciò che mi sono riproposto? La funzione set_v() è indispensabile e va inserita nel costruttore della classe facendo attenzione a non richiamarla più volte previo adeguato controllo?

  • Re: Inizializzazione dati membro statici di una classe [C++]

    Secondo me va bene così. Nel caso particolare sarebbe risparmio di istruzioni più che attenzione, tanto sono numeri a caso

  • Re: Inizializzazione dati membro statici di una classe [C++]

    @Nippolo mi riferivo ai dati membro statici. Vanno definiti in un file cpp come hai fatto tu (con o senza inizializzazione), altrimenti darà errore di linking. 

    Anche le variabili che non sono classi hanno un costruttore di default che, se chiamato, forza l'inizializzazione a zero. Nel tuo caso, essendo una variabile static, viene fatto in automatico e non serve chiamarlo (non ci avevo pensato prima).

    //a e b vengono sempre inizializzate a 0
    int a{};
    int b=int();
    
    int c; //può essere 0 oppure no a seconda dello scopo in cui viene dichiarata

    Se l'inizializzazione è più complessa e richiede un ciclo, puoi usare il metodo della variabile bool, oppure incapsulare il vettore in una classe il cui costruttore di default avvia il ciclo.

    Il metodo della bool è simile a come hai fatto tu (che però è sbagliato, perché la if(!v[0]) controlla se il primo elemento è uguale a zero).

    class A
    {
    private:
        int n;
        static bool isInitialised;
        static int v[10];
        static void set_v();
    
    public:
        A(const int N);
        void fun();
    };
    bool A::isInitialised=false;
    int A::v[10];
    
    A::A(const int N)
    {
        if(!isInitialised)
        {
            set_v();
            isInitialised= true;
        }
        n = N;
    }
  • Re: Inizializzazione dati membro statici di una classe [C++]

    Perfetto, grazie ad entrambi!

    01/06/2023 - Alexv ha scritto:


    Il metodo della bool è simile a come hai fatto tu (che però è sbagliato, perché la if(!v[0]) controlla se il primo elemento è uguale a zero).

    Sì, avevo intuito a cosa ti riferissi quando nel precedente post hai proposto di introdurre una variabile booleana statica di controllo, ma come già detto in precedenza l'ho ritenuta superflua in quanto tenendo conto dell'inizializzazione di default a zero dei membri statici e considerando che dopo aver richiamato la funzione get_v() ho la certezza che tutti gli elementi di v siano >0, allora ho optato per un semplice if(!v[0]), che sinceramente non capisco perché dovrebbe essere sbagliato.

  • Re: Inizializzazione dati membro statici di una classe [C++]

    01/06/2023 - Nippolo ha scritto:


    Perfetto, grazie ad entrambi!

    01/06/2023 - Alexv ha scritto:


    Il metodo della bool è simile a come hai fatto tu (che però è sbagliato, perché la if(!v[0]) controlla se il primo elemento è uguale a zero).

    Sì, avevo intuito a cosa ti riferissi quando nel precedente post hai proposto di introdurre una variabile booleana statica di controllo, ma come già detto in precedenza l'ho ritenuta superflua in quanto tenendo conto dell'inizializzazione di default a zero dei membri statici e considerando che dopo aver richiamato la funzione get_v() ho la certezza che tutti gli elementi di v siano >0, allora ho optato per un semplice if(!v[0]), che sinceramente non capisco perché dovrebbe essere sbagliato.

    Parlavo in generale. Non ero sicuro che avessi chiaro il significato di !v[0]. Nel tuo caso è giusto. 

Devi accedere o registrarti per scrivere nel forum
8 risposte