2010-10-14 15 views
7

Supongamos que tengo una estructura de C++ que tiene tanto variables miembro no-POD POD y:¿Hay alguna manera de hacer un valor de estructura de C++: inicializar todas las variables de miembro de POD?

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

y para que mi programa para producir un comportamiento reproducible quiero tener todas las variables miembro inicializados en la construcción. Puedo usar una lista de inicialización para que:

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

el problema es tan pronto como tengo que cambiar mi estructura y añadir una nueva variable miembro de POD (digamos bool Bool) corro el riesgo de olvidar para añadirlo a la lista de inicialización. Entonces, la nueva variable miembro no se inicializará en valor durante la construcción de la estructura.

Además no puede utilizar el memset() truco:

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

porque llamando memset() para sobrescribir variables miembro-POD no ya construidas pueden romper esos.

¿Hay alguna forma de imponer la inicialización de valor de todas las variables miembro POD sin agregar explícitamente su inicialización en este caso?

+0

recomendaría cada miembro ser 'const' Especialmente cuando todos son 'públicos', realmente tiene sentido forzar la inmutabilidad. Puede usar la sintaxis de inicialización de array para crear instancias: 'Struct s = {" ... ", 0};' –

+0

@Daniel: ¿Y cuándo quiero ponerlo en un contenedor? – GManNickG

+0

@GMan: en este caso, lo colocaría en un 'std :: shared_ptr'. O tal vez decida encapsular adecuadamente los miembros y eliminar el 'const'. –

Respuesta

10

La manera más limpia sería escribir la clase de plantilla de auto-inicializaron initialized<T>:

EDITAR: Me doy cuenta ahora que se puede hacer aún más flexible al permitirle declarar initialized<Struct>. Esto significa que puede declarar la inicialización sin modificar el original Struct. La inicialización predeterminada 'T()' se inspiró en la respuesta 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; 
} 

Esto compila, pero puede necesitar más operadores de conversión, la manipulación de palabras clave como volátil, etc, pero se entiende la idea.

+1

Hmmm. Se ve bien, pero ¿cuál es el propósito de hacer 'value' privado y luego proporcionar acceso completo a él de todos modos? ¿No sería más limpio simplemente hacerla pública y eliminar las conversiones? – sharptooth

+1

@sharptooth: La idea es que puede usar 'initialized ' casi como 'int'. Por ejemplo, 'initialized a; int b = a; 'funciona. Sin los operadores de conversión, necesitaría acceder al miembro 'value' explícitamente. –

+1

@Martin B: Sí, tienes razón sobre el acceso directo, no pensé en eso. Hacer aún privado el 'valor' no tiene sentido. – sharptooth

10

Vinculado Pregunta here

¿Hay una manera de hacer cumplir valor de inicialización de todas las variables miembro POD sin agregar explícitamente su inicialización en este caso?

No estoy seguro de si algo así es posible [directamente] o no, pero las siguientes obras

[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 Eres afortunado y obtienes ceros porque la memoria en la que 'i' se colocó pasó a cero. Esto no está garantizado por el estándar. –

+7

@Martin B: Creo que está garantizado por C++ 03. Por favor, eche un vistazo a mi pregunta [aquí] (http://stackoverflow.com/questions/3931312/value-initialization-and-non-pod-types) –

+4

Aprendí algo allí - mis disculpas. Estoy eliminando el voto a favor y agregando un voto positivo. –

-1

Puede añadir una estructura de base:

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

Y entonces su estructura derivada de esta estructura de base, en primer lugar, si usted tiene más de uno estructuras de base,

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

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

Esto lleva a UB. No se puede 'memset' sobre un tipo que no sea POD, como' std :: string'. – GManNickG

Cuestiones relacionadas