2010-10-14 18 views
7

Supposons que j'ai une struct C++ qui a à la fois POD et des variables non membres POD:Existe-t-il un moyen de créer une valeur de structure C++: initialise toutes les variables de membre POD?

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

et pour que mon programme pour produire un comportement reproductible Je veux avoir toutes les variables membres initialisés à la construction. Je peux utiliser une liste d'initialiseur pour que:

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

le problème est que dès que je dois changer mon struct et ajouter une nouvelle variable membre POD (par exemple bool Bool) je risque d'oublier de l'ajouter à la liste des initialiseur. Ensuite, la nouvelle variable membre ne sera pas initialisée lors de la construction de la structure.

Aussi je ne peux pas utiliser l'astuce memset():

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

parce que l'appel memset() à écraser les variables déjà construites membres non-POD peuvent briser ceux-ci.

Existe-t-il un moyen d'appliquer l'initialisation de valeur de toutes les variables de membre POD sans ajouter explicitement leur initialisation dans ce cas?

+0

Je recommande chaque membre être 'const'. Surtout quand ils sont tous «publics», il est logique de forcer l'immutabilité. Vous pouvez utiliser la syntaxe d'initialisation de tableau pour créer des instances: 'Struct s = {" ... ", 0};' –

+0

@Daniel: Et quand je veux le mettre dans un conteneur? – GManNickG

+0

@GMan: Je le placerais dans un 'std :: shared_ptr' dans ce cas. Ou peut-être décider d'encapsuler correctement les membres et supprimer le 'const'. –

Répondre

10

La façon la plus propre serait d'écrire la classe de modèle auto-initialzed initialized<T>:

EDIT: Je réalise maintenant qu'il peut être encore plus flexible en vous permettant de déclarer initialized<Struct>. Cela signifie que vous pouvez déclarer l'initialisation sans modifier l'original Struct. L'initialisation par défaut 'T()' a été inspirée par la réponse de 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; 
} 

Cette compile, mais peut-être plus les opérateurs de conversion, le traitement des mots-clés comme volatile, etc. Mais vous voyez l'idée.

+1

Hmmm. Ça a l'air bien, mais quel est le but de privatiser 'value' et de lui donner un accès complet de toute façon? Ne serait-il pas plus propre de le rendre public et de supprimer les conversions? – sharptooth

+1

@sharptooth: L'idée est que vous pouvez utiliser 'initialized ' presque comme un 'int'. Par exemple, 'initialisé a; int b = a; 'fonctionne. Sans les opérateurs de conversion, vous devez accéder explicitement au membre 'value'. –

+1

@ Martin B: Oui, vous avez raison à propos de l'accès direct, je n'y ai pas pensé. Rendre encore «value» privé n'a aucun sens. – sharptooth

10

Lié Question here

Est-il possible d'appliquer la valeur initialisation de toutes les variables membres POD sans ajouter explicitement leur initialisation dans ce cas?

Je ne sais pas si quelque chose comme ça est possible [directement] ou non, mais les travaux suivants

[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 Vous avez de la chance et obtenez des zéros car la mémoire dans laquelle j'ai été placé s'est avérée être initialisée à zéro. Ceci n'est pas garanti par la norme. –

+7

@Martin B: Je pense que c'est garanti par C++ 03. S'il vous plaît jeter un oeil à ma question [ici] (http://stackoverflow.com/questions/3931312/value-initialization-and-non-pod-types) –

+4

J'ai appris quelque chose là - mes excuses. Je supprime le downvote et ajoute un upvote. –

-1

Vous pouvez ajouter une struct de base:

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

Et puis votre struct dérivé de cette structure de base, d'abord si vous avez plus d'un struct de base,

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

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

Cela conduit à UB. Vous ne pouvez pas 'memset' sur un type non-POD, comme' std :: string'. – GManNickG