2009-06-19 12 views
6

Questa è una classe C++ che ho creato con n numero di puntatori.facendo numerosi puntatori NULL allo stesso tempo

class SomeClass 
{ 
private: 
     int* ptr1; 
     int* ptr2; 
     ... 
     int* ptrn; 

private: 
     // constructors, destructors, and methods 
}; 

Durante la fase di inizializzazione, Voglio fare tutte quelle puntatori punto a NULL (o fare puntatori punto a NULL per impostazione predefinita quando sono dichiarate), piuttosto che farlo:

void SomeClass::MakePtrNull() 
{ 
     ptr1 = NULL; 
     ptr2 = NULL; 
     ... 
     ptrn = NULL; 
} 

C'è qualsiasi metodo facile per raggiungere questo obiettivo? Mi sto solo chiedendo se ci sono modi per evitare di digitare n righe di ptr = NULL; nella mia funzione. Grazie in anticipo.

AGGIUNTO sulla base delle risposte che ho ricevuto finora: Purtroppo, questi puntatori devono essere separati, in quanto sono utilizzati per scopi diversi. Ho fatto i nomi dei puntatori in quanto tali solo per capire cosa sto cercando di fare, ma ogni puntatore ha uno scopo completamente diverso. Credo che dovrei farli puntare a NULL come ho già fatto. Grazie per le tue risposte.

+0

Si noti che se la classe non ha un costruttore dichiarato dall'utente, SomeClass() avrà tutti i puntatori zero. Ciò significa che puoi semplicemente fare * this = SomeClass(); e farebbe puntare tutti i puntatori a zero. –

+0

@litb, nei miei test, solo le istanze statiche di SomeClass hanno azzerato tutti i puntatori; le istanze automatiche e di heap ottengono tutto ciò che si trova nella pila o nell'heap. –

+0

supponendo che non ci sia un costruttore dichiarato dall'utente, quindi SomeClass() è inizializzato in contrapposizione a "a" in {SomeClass a; }. Il valore SomeClass() inizializza, in modo ricorsivo, tutti i suoi membri. Ciò renderà qualsiasi membro del puntatore ai puntatori nulli. Se si definisce una variabile automatica e non ha un costruttore dichiarato dall'utente, non viene inizializzata. Dovresti fare per esempio {SomeClass a = SomeClass(); } –

risposta

6

Perché non si utilizza un vettore o un vettore piuttosto che creare n puntatori nominati singolarmente? Quindi puoi annullare il tutto in un ciclo breve.

5

Si può fare questo:

void SomeClass::MakePtrNull() 
{ 
     ptr1 = ptr2 = ptr3 = ... = ptrn = NULL; 
} 
3

In primo luogo, la tecnica che non lavoro:

Calling memset per impostare l'intero oggetto a zero non lo farà. Innanzitutto, causerà un sacco di problemi se la tua funzione ha una o più funzioni virtuali e, in secondo luogo, non è garantito che un puntatore nullo sia rappresentato da un modello di bit di tutti gli zeri.

Quello che probabilmente farei nel tuo caso è memorizzare i puntatori in un array o in un vettore. Quindi è possibile utilizzare la funzione std::fill per impostarli tutti su NULL. (Oppure si può usare un loop se si preferisce)

Naturalmente, se è necessario farlo abbastanza spesso, può valere la pena scrivere una classe wrapper che si comporta come puntatore, ma che imposta su NULL nel suo valore predefinito costruttore.

Oppure è possibile utilizzare boost :: opzionale che funziona essenzialmente in questo modo. (Anche se non è specifica per i puntatori)

+1

Si dice che un puntatore nullo non è garantito per essere presentato da un modello di bit di tutti zeri, implica che un controllo if come questo: if (ptr1) non è un modo sicuro per determinare che un puntatore non è nullo ? –

+0

Sì, si prega di elaborare su quale scenario 0x0 non è un indirizzo valido 'nessuna memoria allocata qui'. Inoltre, se struct/class (così come le sue classi genitore) non ha metodi virtuali, la sua dimensione di sarà esattamente la somma delle dimensioni dei suoi membri. –

+1

@ savage. Questo è sicuro. Un ptr NULL deve valutare falso, ma l'implementazione può rappresentarlo nella memoria a piacere. In pratica praticamente tutti usano 0, perché anche un NULL ptr deve essere convertito in numero intero come 0 ed è in genere più semplice ed efficiente non modificare il modello di bit. @Shane: la struttura deve essere POD per quello che dici essere garantito dallo standard. Ci sono altre cose oltre ai metodi virtuali che possono far sì che una struttura non sia POD e avere qualsiasi classe base sia una di queste. –

2

perché non utilizzare un costruttore di default:

SomeClass::SomeClass() : ptr1(NULL), ptr2(NULL), ... 
{ 

} 

Si potrebbe anche fare:

ptr1 = ptr2 = ptr3 = NULL; 
0

Utilizzare un vettore per questo (perché dai suoni della in futuro non avrai più bisogno di modificare la lista e avrai bisogno di un accesso casuale). Si può fare in questo modo:

class PointerList 
{ 
private: 
    typedef std::vector<int*> IntPtrVector; 
    IntPtrVector m_ptrVec; 

public: 
    PointerList() 
    { 
     m_ptrVec.reserve(5); 
     for (int i = 0; i < 5; i++) 
      m_ptrVec.push_back(NULL); 
    } 

    int* getPointer(int index) 
    { 
     return m_ptrVec[index]; 
    } 

    void setPointer(int index, int* ptr) 
    { 
     assert(index <= 4); 
     m_ptrVec[index] = ptr; 
    } 
}; 

EDIT

anche se ad essere onesti questo puzza di ghettoness. Sei sicuro che il tuo problema richieda questa soluzione? Se approfondisci il tuo problema specifico, forse in un'altra domanda, sono sicuro che puoi ottenere una risposta migliore su come ottenere ciò che desideri in modo più elegante, piuttosto creando un secondo problema.

+0

L'intero punto della domanda è chiedere se posso prendere una via di uscita pigra ancora che funziona. Grazie per il tuo tempo sui suggerimenti però. – stanigator

11

Invece di int *, creare una classe di smart-pointer-like, che funziona esattamente come un int *, ma default-costrutti con NULL:

template <typename T> 
class MyPointer { 
    T *p; 

public: 
    MyPointer() : p(NULL) { } 
    MyPointer(T *o) : p(o) { } 
    operator T*() const { return p; } 
    // ...and the rest of the traditional smart-pointer operators 
}; 

Quindi, utilizzare il metodo nella classe:

class SomeClass 
{ 
private: 
     MyPointer<int> ptr1; 
     MyPointer<int> ptr2; 
     ... 
     MyPointer<int> ptrn; 

private: 
     // constructors, destructors, and methods 
}; 

Ogni variabile del tipo MyPointer<int> verrà automaticamente inizializzata correttamente nei costruttori di SomeClass, senza necessità di digitazione aggiuntiva. Se non hai dimenticato o implementato in modo errato uno qualsiasi dei metodi di MyPointer, funzionerà esattamente come un normale puntatore e avrà esattamente le stesse dimensioni e le stesse prestazioni.

+2

+1 per utilizzare il sistema di tipi per esprimere esattamente l'intento di programmazione. –

+0

Un altro vantaggio è che tu ei gestori del codice non sarà necessario inizializzare i puntatori in ogni costruttore, o ricordarsi di aggiornare gli elenchi di inizializzatori nel caso in cui il numero o il nome dei membri di MyPointer cambi. –

+0

Inoltre - 0 runtime overhead – Eclipse

1

È possibile inserire i puntatori in una struttura e quindi memset() la struct quando necessario. I puntatori sono ancora separati, ma hai i mezzi per bersagliarli come una singola unità senza influenzare il resto della tua classe. Per esempio:

struct MyPointers 
{ 
    int* ptr1; 
    int* ptr2; 
    ... 
    int* ptrn; 
}; 

class SomeClass 
{ 
private: 
    MyPointers ptrs; 
    ... 
}; 

void SomeClass::MakePtrNull() 
{ 
    memset(&ptrs, 0, sizeof(ptrs)); 
} 
+1

memset non funziona in questo modo. vedi la risposta di jalf. –

3

vi consiglio di fare quanto segue, se si deve mantenere i puntatori separatamente (probabilmente l'esigenza più pressante sarebbe se i puntatori possono avere diversi tipi)

class SomeClass { 
    struct Pointers { 
     int* ptr1; 
     int* ptr2; 
     float* ptrn; 
    } ptrs; 

public: 
    void MakePtrNull(); 
}; 

void SomeClass::MakePtrNull() 
{ 
    // clears all pointers at once 
    ptrs = Pointers(); 
} 

Questo funziona, perché l'inizializzazione del valore per le classi che non hanno un costruttore dichiarato dall'utente valuterà l'inizializzazione di tutti i suoi membri. L'inizializzazione del valore di un puntatore creerà un puntatore nullo.

+0

Questa è una grande tecnica. +1 –

Problemi correlati