c++ - library - El miembro de la Unión tiene un constructor de copia no trivial
string c++ example (5)
Desafortunadamente, no puede usar tipos no POD (datos antiguos) en una unión. Una solución bastante típica y simple para esto es envolver la unión en una estructura y mover la instancia que no es POD desde dentro de la unión a la estructura.
Por ejemplo:
struct Value {
union {
int intValue;
double doubleValue;
void *pointerValue;
};
std::string stringValue;
};
Value value;
// Demonstration of accessing members:
value.intValue = 0;
value.doubleValue = 0.0;
value.pointerValue = NULL;
value.stringValue = "foo";
Sin embargo, pagará un precio por esto: la huella de memoria de la estructura de Value
será mayor que la de la unión original.
Esta pregunta ya tiene una respuesta aquí:
Tengo una unión que se parece a esto:
union {
int intValue;
double doubleValue;
std::string stringValue;
void *pointerValue;
} values;
Cuando lo compilo, recibo este mensaje de error (sí, hice #include <string>
):
./Value.hh:19:19: error: union member ''stringValue'' has a non-trivial copy constructor
std::string stringValue;
^
/Developer/SDKs/MacOSX10.7.sdk//usr/include/c++/4.2.1/bits/basic_string.h:434:7: note: because
type ''std::basic_string<char>'' has a user-declared copy constructor
basic_string(const basic_string& __str);
^
Lo compilo usando este comando:
$ clang++ *.cc -isysroot /Developer/SDKs/MacOSX10.7.sdk/ -shared
¿Cómo puedo usar un std::string
en una unión?
No puedes poner un std::string
en una unión. No está permitido por el lenguaje C ++ porque no es seguro. Tenga en cuenta que la mayoría de std::string
implementaciones de std::string
tienen un puntero a alguna memoria dinámica que contiene el valor de la cadena. Considere también que no hay manera de saber qué miembro del sindicato está actualmente activo.
Una implementación no puede llamar al destructor de std::string
, porque no sabe que el objeto std::string
es el miembro actualmente activo, pero si no llama al destructor, entonces la memoria se perderá.
No se puede.
Una unión combina dos piezas de funcionalidad: la capacidad de almacenar un objeto que puede ser de un número selecto de tipos, y la capacidad de convertir de manera efectiva (y definida por la implementación) entre esos tipos. Podrías poner un entero y ver su representación como un doble. Etcétera.
Debido a que una unión debe admitir estas dos funcionalidades (y por otras razones, como poder construir una), una unión le impide hacer ciertas cosas. Es decir, no puedes poner objetos "vivos" en ellos. Cualquier objeto que esté "vivo" lo suficiente como para que necesite un constructor de copia no predeterminado (entre muchas otras restricciones) no puede ser miembro de una unión.
Después de todo, un objeto de unión no tiene realmente el concepto de qué tipo de datos almacena realmente. No almacena un tipo de datos; Los almacena todos , al mismo tiempo. Depende de usted poder pescar el tipo correcto. Entonces, ¿cómo podría copiar razonablemente un valor de unión en otro?
Los miembros de un sindicato deben ser de tipo POD (datos antiguos). Y mientras C ++ 11 afloja esas reglas, los objetos aún deben tener un constructor de copia predeterminado (o trivial). Y el constructor de copia de std::string
no es trivial.
Lo que probablemente quieras es un boost::variant
. Ese es un objeto que puede almacenar varios tipos posibles, al igual que una unión. Sin embargo, a diferencia de una unión, es de tipo seguro. Por lo tanto, sabe lo que está realmente en la unión; por lo tanto, puede copiarse a sí mismo y, de lo contrario, comportarse como un objeto C ++ normal.
Según la norma C ++ §9.5.1:
Un objeto de una clase con un constructor no trivial, un constructor de copia no trivial, un destructor no trivial o un operador de asignación de copia no trivial no puede ser miembro de una unión.
Por lo tanto, los miembros de una unión no pueden tener constructores, destructores, funciones de miembros virtuales o clases base. Por lo tanto, no puede usar std :: string como miembro de union.
Solución alternativa:
Puedes usar boost :: variant o boost :: any .
union
no puede tener miembros de los siguientes tipos §9.5 / 1:
Un objeto de una clase con un constructor no trivial (12.1), un constructor de copia no trivial (12.8), un destructor no trivial (12.4), o un operador de asignación de copia no trivial (13.5.3, 12.8) no puede ser miembro de una unión, ni puede una matriz de tales objetos.
Entonces, o bien define un puntero a std :: string como:
union {
int intValue;
double doubleValue;
std::string *stringValue; //pointer
void *pointerValue;
} values;
o, use boost union que se conoce como boost::variant