online ejemplos descargar definicion caracteristicas c++

ejemplos - c++ online



¿Por qué el compilador no permite std:: string dentro de la unión? (5)

De la especificación de 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.

El motivo de esta regla es que el compilador nunca sabrá cuál de los destructores / constructores llama, ya que nunca sabe realmente cuál de los posibles objetos se encuentra dentro de la unión.

Quiero usar una cuerda dentro de Union. si escribo como abajo

union U { int i; float f; string s; };

El compilador da error diciendo que U :: S tiene un constructor de copia.

Leí alguna otra publicación para encontrar formas alternativas de resolver este problema. Pero quiero saber por qué el compilador no permite esto en primer lugar?

EDITAR: @KennyTM: en cualquier unión, si el miembro se inicializa, otros tendrán valores basura, si ninguno se inicializa, todos tendrán valores basura. Creo que la unión etiquetada solo proporciona cierta comodidad para acceder a los valores válidos de Union. Tu pregunta: ¿cómo escribes tú o el compilador un constructor de copias para la unión anterior sin información adicional? sizeof (cadena) da 4 bytes. En base a esto, el compilador puede comparar el tamaño de otros miembros y asignar la asignación más grande (4 bytes en nuestro ejemplo). La longitud interna de la cuerda no importa porque se almacenará en una ubicación separada. Deje que la cuerda sea de cualquier longitud. Todo lo que la Unión tiene que saber es invocar el constructor de copia de clase de cadena con el parámetro de cadena. En cualquier forma en que el compilador encuentre que se debe invocar el constructor de copia en el caso normal, se seguirá un método similar incluso cuando la cadena esté dentro de Unión. Así que estoy pensando que el compilador podría hacer, asignar 4 bytes. Entonces, si se asigna una cadena a s, la clase de cadena se encargará de la asignación y copia de esa cadena utilizando su propio asignador. Entonces tampoco hay posibilidad de corrupción en la memoria.

¿La cadena no existe en el momento del desarrollo de la Unión en el compilador? Entonces la respuesta aún no está clara para mí. Soy un nuevo socio en este sitio, si algo está mal, por favor discúlpeme.


En C ++ 98/03, los miembros de una unión no pueden tener constructores, destructores, funciones de miembros virtuales o clases base.

Entonces, básicamente, solo puedes usar tipos de datos incorporados, o PODs

Tenga en cuenta que está cambiando en C ++ 0x: uniones sin restricciones

union { int z; double w; string s; // Illegal in C++98, legal in C++0x. };


La basura se introduce si

  1. asignar una cadena
  2. luego asigna un int o float
  3. a continuación, una cadena de nuevo

cadena maneja la memoria en otro lugar. Esta información probablemente sea un puntero. Este puntero está guardado cuando se asigna el int. Asignar una nueva cadena debería destruir la cadena anterior, lo cual no es posible.

El segundo paso debe destruir la cadena, pero no lo sabe, si ha habido una cadena.

Obviamente, han encontrado una solución para este problema mientras tanto.


Piénsalo. ¿Cómo sabe el compilador qué tipo hay en la unión?

No es así La operación fundamental de una unión es esencialmente un reparto de bits. Las operaciones con los valores contenidos en las uniones solo son seguras cuando cada tipo se puede llenar con basura. std::string no puede, porque daría lugar a daños en la memoria. Utilice boost::variant o boost::any .


Porque tener una clase con un constructor no trivial (copy /) en una unión no tiene sentido. Supongamos que tenemos

union U { string x; vector<int> y; }; U u; // <--

Si U fuera una estructura, ux y uy se inicializarían en una cadena vacía y un vector vacío, respectivamente. Pero los miembros de un sindicato comparten la misma dirección. Por lo tanto, si ux se inicializa, uy contendrá datos no válidos, al igual que el reverso. Si ambos no se inicializan, entonces no pueden ser utilizados. En cualquier caso, tener estos datos en una unión no se puede manejar fácilmente, por lo que C ++ 98 elige denegar esto: (§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 pueden ser un miembro de una unión, ni tampoco una variedad de tales objetos.

En C ++ 0x esta regla se ha relajado (§9.5 / 2):

Como máximo, un miembro de datos no estáticos de una unión puede tener un inicializador de llaves o igual . [ Nota: si algún miembro de una unión no estático tiene un constructor predeterminado no trivial (12.1), copia el constructor (12.8), mueve el constructor (12.8), copia el operador de asignación (12.8), mueve el operador de asignación (12.8), o destructor (12.4), la función miembro correspondiente de la unión debe ser proporcionada por el usuario o se eliminará implícitamente (8.4.3) para la unión. - nota final ]

pero aún no es posible crear (corregir) con / destructores para la unión, por ejemplo, ¿cómo usted o el compilador escriben un constructor de copia para la unión anterior sin información adicional? Para asegurarse de qué miembro de la unión está activo, necesita una unión etiquetada , y debe manejar la construcción y destrucción manualmente, por ejemplo

struct TU { int type; union { int i; float f; std::string s; } u; TU(const TU& tu) : type(tu.type) { switch (tu.type) { case TU_STRING: new(&u.s)(tu.u.s); break; case TU_INT: u.i = tu.u.i; break; case TU_FLOAT: u.f = tu.u.f; break; } } ~TU() { if (tu.type == TU_STRING) u.s.~string(); } ... };

Pero, como ha mencionado @DeadMG , esto ya está implementado como boost::variant or boost::any .