2010-01-17 16 views
13

Sto provando a creare una classe che ha un membro privato che è una matrice. Non conosco la dimensione della matrice e non lo sarà fino a quando il valore non viene passato al costruttore. Qual è il modo migliore per definire la funzione di costruzione della classe e la definizione nel file .h per consentire questa dimensione variabile dell'array?Matrice come membro privato della classe

risposta

10

Se si desidera un array "reale" in stile C, è necessario aggiungere un membro privato dell'indicatore alla classe e allocare dinamicamente la memoria per esso nel costruttore (con nuovo). Ovviamente non devi dimenticare di liberarlo nel distruttore.

class YourClass 
{ 
    private: 
    int * array; 
    size_t size; 

    // Private copy constructor operator to block copying of the object, see later 
    // C++03: 
    YourClass(const YourClass &); // no definition 
    // C++11: 
    YourClass(const YourClass&) = delete; 

    public: 
    YourClass(size_t Size) : array(new int[Size]), size(Size) 
    { 
     // do extra init stuff here 
    }; 

    ~YourClass() 
    { 
     delete [] array; 
    } 
}; 

per fare questo lavoro più facile, si può considerare di utilizzare un puntatore intelligente (ad esempio, un boost::scoped_array in C++ 03, o semplice std::unique_ptr in C++ 11), che si può inizializzare utilizzando l'inizializzazione elenco prima del costruttore o semplicemente nel costruttore.

class YourClass 
{ 
    private: 
    boost::scoped_array<int> array; // or in C++11 std::unique_ptr<int[]> array; 
    size_t size; 
    public: 
    YourClass(size_t Size) : array(new int[Size]), size(Size) 
    { 
     // do extra init stuff here 
    } 

    // No need for a destructor, the scoped_array does the magic 
}; 

Entrambe queste soluzioni producono oggetti noncopyable (non è stato specificato se dovessero essere copiabile e la loro copia semantica); se la classe non deve essere copiata (cosa che accade più volte), entrambi sono ok e il compilatore genererà un errore se si tenta di copiare/assegnare una classe a un'altra, nel primo caso perché la copia predefinita il costruttore è stato sovraccaricato con uno privato (o cancellato in C++ 11), nel secondo caso perché boost::scoped_array e std::unique_ptr non sono copiabili.

Se, invece, si desidera disporre di oggetti copiabili, è necessario decidere se si desidera creare una copia che condivide l'array (quindi, solo una copia puntatore) o se si desidera creare un nuovo array separato per l'altro oggetto.

Nel primo caso, è necessario prestare molta attenzione prima di liberare la memoria allocata, poiché altri oggetti potrebbero utilizzarla; un contatore di riferimento è la soluzione più comune. Puoi essere aiutato in questo da boost::shared_array (o std::shared_ptr in C++ 11), che fa tutto il monitoraggio funziona automaticamente per te.

Se invece si desidera eseguire una "copia profonda", sarà necessario allocare la nuova memoria e copiare tutti gli oggetti dell'array sorgente nell'array di destinazione. Questo non è completamente banale da fare correttamente, e di solito è realizzato attraverso il "copy and swap idiom".

Eppure, la soluzione più semplice è quella di utilizzare un std::vector come membro privato: sarebbe gestire tutte le cose allocazione/deallocazione di per sé, costruendo/autodistruggersi correttamente quando l'oggetto della vostra classe è costruito/distrutto. Inoltre, implementa la semantica della copia profonda fuori dalla scatola. Se è necessario consentire ai chiamanti di accedere al vettore di sola lettura, è possibile scrivere un getter che restituisce un riferimento const_iterator o const all'oggetto vector.

+1

Per gli array, dovrai assicurarti di usare ' scoped_array', non 'scoped_ptr'. –

+0

corretto, grazie. Ottengo sempre la cancellazione [], ma a volte mi sono dimenticato delle versioni dell'array dei puntatori intelligenti. –

+0

L'unico snigging è se YourClass sta per essere copiato, perché scoped_ * non è copiato in boost. Ciò non è specificato nella domanda comunque, quindi +1 comunque. – Skurmedel

2

L'utilizzo di un vettore std :: è la migliore. Se hai bisogno di passarlo a una funzione che si aspetta un puntatore a un array (come fa spesso il GSL), puoi ancora passare &vec[0] ...

Problemi correlati