2010-10-14 4 views
7

Supponiamo che io sono un ++ struct C che ha sia POD e non-POD variabili membro:C'è un modo per rendere un valore struct C++-inizializzare tutte le variabili dei membri POD?

struct Struct { 
    std::string String; 
    int Int; 
}; 

e in ordine per il mio programma per la produzione di un comportamento riproducibile voglio avere tutte le variabili membro inizializzate in costruzione. Posso usare una lista di inizializzazione per questo:

Struct::Struct() : Int() {} 

il problema è, non appena ho bisogno di cambiare il mio struct e aggiungere una nuova variabile membro POD (diciamo bool Bool) rischierei dimenticare di aggiungere alla lista di inizializzazione. Quindi la nuova variabile membro non verrà inizializzata in base al valore durante la costruzione della struct.

Inoltre non posso usare il memset() trucco:

Struct::Struct() 
{ 
    memset(this, 0, sizeof(*this)); //can break non-POD member variables 
} 

perché chiamando memset() per sovrascrivere le variabili membro già costruiti non-POD può rompere quelli.

C'è un modo per applicare l'inizializzazione del valore di tutte le variabili membro POD senza aggiungere esplicitamente la loro inizializzazione in questo caso?

+0

mi sento di raccomandare ogni membro essere 'const'. Soprattutto quando sono tutti pubblici, è davvero sensato forzare l'immutabilità. È possibile utilizzare la sintassi di inizializzazione dell'array per creare istanze: 'Struct s = {" ... ", 0};' –

+0

@Daniel: E quando voglio inserirlo in un contenitore? – GManNickG

+0

@GMan: lo posizionerei in un 'std :: shared_ptr' in questo caso. O forse decidi di incapsulare correttamente i membri e rimuovere 'const'. –

risposta

10

Il modo più pulito sarebbe quella di scrivere l'auto-initialzed classe template initialized<T>:

EDIT: Mi rendo conto ora può essere reso ancora più flessibile, consentendo di dichiarare initialized<Struct>. Ciò significa che è possibile dichiarare l'inizializzazione senza modificare l'originale Struct. L'inizializzazione predefinita 'T()' è stata ispirata dalla risposta di Prasoons.

template<class T> 
struct initialized 
{ 
public: 

    initialized() 
     { value = T(); } 

    initialized(T t) 
     { value = t; } 

    initialized(const initialized<T>& x) 
     { value = x.value; } 

    T* operator &() { return &value; } 

    operator T&() { return value; }  

private: 
    T value; 
}; 


struct PodStruct 
{    
    std::string String;  
    int Int; 
}; 


struct GlorifiedPodStruct 
{    
    std::string String;  
    initialized<int> Int; 
}; 

void Test() 
{ 
    GlorifiedPodStruct s; 
    s.Int = 1; 
    int b = s.Int; 
    int * pointer = &s.Int; 

    initialized<PodStruct> s2; 
} 

Questo compila, ma potrebbe essere necessario più operatori di conversione, la gestione delle parole chiave come volatile, ecc, ma si ottiene l'idea.

+1

Hmmm. Sembra buono, ma quale è lo scopo di rendere "value" privato e quindi di fornire comunque pieno accesso ad esso? Non sarebbe più pulito renderlo pubblico e rimuovere le conversioni? – sharptooth

+1

@sharptooth: L'idea è che puoi usare 'initialized ' quasi come un 'int'. Ad esempio, 'inizializzato a; int b = a; 'funziona. Senza gli operatori di conversione, è necessario accedere esplicitamente al membro 'value'. –

+1

@ Martin B: Sì, hai ragione sull'accesso diretto, non ci ho pensato. Rendere il valore privato non ha senso. – sharptooth

10

Linked Domanda here

C'è un modo per far rispettare valore di inizializzazione di tutte le variabili membro POD senza aggiungere in modo esplicito la loro inizializzazione in questo caso?

io non sono sicuro se sia possibile [direttamente] o meno qualcosa di simile, ma funziona il seguente

[email protected] ~ $ cat check.cpp && clang++ check.cpp && ./a.out 
#include <iostream> 
struct Struct { 
    std::string String; 
    int Int; 
    bool k; 
    // add add add 
}; 

struct InStruct:Struct 
{ 
    InStruct():Struct(){} 
}; 

int main() 
{ 
    InStruct i; 
    std::cout<< i.k << " " << i.Int << std::endl; 
} 
0 0 
[email protected] ~ $ 
+0

-1 Sei fortunato e stai prendendo zeri perché la memoria in cui si trovava 'i' è stata inizializzata a zero. Questo non è garantito dallo standard. –

+7

@ Martin B: Penso che sia garantito da C++ 03. Per favore dai un'occhiata alla mia domanda [qui] (http://stackoverflow.com/questions/3931312/value-initialization-and-non-pod-types) –

+4

Ho imparato qualcosa lì - le mie scuse. Sto rimuovendo il downvote e aggiungendo un upvote. –

-1

È possibile aggiungere una struttura di base:

struct PODStruct 
{ 
    PODStruct(unsinged int count) { memset(this, 0, count);} 
}; 

E poi il tuo struct derivato da questo struct base, il primo posto se si dispone di più di una le strutture di base,

struct Struct : PODStruct 
{ 
    Struct(); 
    std::string Str; 
    int Int; 
} 

Struc::Struct() : PODStruct(sizeof(Struct)) 
{ 
} 
+2

Questo porta a UB. Non puoi 'memset' su un tipo non POD, come' std :: string'. – GManNickG