¿Cuál es el propósito de usar un sindicato con un solo miembro?

4 minutos de lectura

avatar de usuario
xiaoming-qxm

cuando estaba leyendo código fuente de la estrella de marnoté que hay una estructura sindical llamada tx_side que tiene un solo miembro. ¿Es esto un truco para lidiar con un problema determinado?

Para tu información, pego el tx_side estructura a continuación:

union tx_side {
    tx_side() {}
    ~tx_side() {}
    void init() { new (&a) aa; }
    struct aa {
        std::deque<work_item*> pending_fifo;
    } a;
} _tx;

  • Posible duplicado de stackoverflow.com/questions/26572432/….

    –Max Langhof

    27 de noviembre de 2019 a las 9:32

  • @MaxLanghof Esta pregunta y las respuestas correspondientes no mencionaron el propósito de usar dicha estructura de unión.

    – xiaoming-qxm

    27 de noviembre de 2019 a las 9:37

  • ¿Tiene un ejemplo para el uso de este miembro?

    – n314159

    27 de noviembre de 2019 a las 9:39

  • Es por eso que en realidad no usé mi voto cerrado vinculante. Pero no estoy seguro de qué espera exactamente de las respuestas a su pregunta que no se derivan directamente de las respuestas de allí. Probablemente el propósito de usar union en vez de struct es una o más de las diferencias entre los dos. Es una técnica bastante oscura, por lo que, a menos que aparezca el autor original de ese código, no estoy seguro de que alguien pueda darle una respuesta autorizada sobre qué problema esperan resolver con esto (si corresponde).

    –Max Langhof

    27 de noviembre de 2019 a las 9:40


  • Mi mejor conjetura es que la unión se usa para retrasar la construcción (lo que no tiene sentido en este caso) o para evitar la destrucción (lo que conduce a una fuga de memoria) de la fifo_pendiente. Pero difícil de decir sin ejemplo de uso.

    – Konstantin Stupnik

    27 de noviembre de 2019 a las 9:53

avatar de usuario
santonegrogato

Porque tx_side es un sindicato, tx_side() no inicializa/construye automáticamente ay ~tx_side() no lo destruye automáticamente. Esto permite un control detallado sobre la vida útil de a y pending_fifoa través de llamadas de colocación-nuevas y manuales de destructor (un hombre pobre std::optional).

Aquí hay un ejemplo:

#include <iostream>

struct A
{
    A() {std::cout << "A()\n";}
    ~A() {std::cout << "~A()\n";}
};

union B
{
    A a;
    B() {}
    ~B() {}
};

int main()
{
    B b;
}

Aquí, B b; no imprime nada, porque a no se construye ni se destruye.

Si B era un struct, B() Llamaría A()y ~B() Llamaría ~A()y no serías capaz de evitar eso.

  • @daoliker no necesariamente aleatorio, sino impredecible para ti. Igual que cualquier otra variable no inicializada. No puedes asumir que es aleatorio; por lo que sabe, podría contener la contraseña del usuario que le pidió que escribiera previamente.

    – usuario253751

    27 de noviembre de 2019 a las 10:20


  • @daoliker: El comentario anterior es demasiado optimista. Los bytes aleatorios tendrían valores en el rango de 0 a 255, pero si lee un byte no inicializado en un int usted puede obtener 0xCCCCCCCC. La lectura de datos no inicializados es un comportamiento indefinido y lo que podría suceder es que el compilador simplemente descarte el intento. Esto no es solo teoría. Debian cometió exactamente este error y rompió su implementación de OpenSSL. Tenían algunos bytes aleatorios reales, agregaron una variable no inicializada y el compilador dijo “bueno, el resultado no está definido, por lo que bien podría ser cero”. El cero obviamente ya no es aleatorio.

    – MSalters

    28 de noviembre de 2019 a las 10:49

  • @MSalters: ¿Tiene una fuente para este reclamo? Porque lo que puedo encontrar sugiere que eso no es lo que sucedió: no fue el compilador el que lo eliminó, sino los desarrolladores. Honestamente, me sorprendería si algún compilador tomara una decisión tan increíblemente mala. (ver stackoverflow.com/questions/45395435/… )

    – Jack Aidley

    28 de noviembre de 2019 a las 12:21


  • @JackAidley: ¿Qué afirmación precisa? Tienes un buen enlace, parece que tengo la historia al revés. OpenSSL entendió mal la lógica y usó una variable no inicializada de tal manera que un compilador podría asumir legalmente cualquier resultado. Debian lo detectó correctamente, pero rompió la solución. En cuanto a los “compiladores que toman decisiones tan malas”; ellos no toman esa decisión. El Comportamiento Indefinido es la mala decisión. Los optimizadores están diseñados para ejecutarse en el código correcto. GCC, por ejemplo, asume activamente que no hay desbordamiento firmado. Asumir que “no hay datos no inicializados” es igualmente razonable; se puede utilizar para eliminar rutas de código imposibles.

    – MSalters

    28 de noviembre de 2019 a las 12:37

  • @JackAidley He encontrado problemas similares a los que @MSalters menciona en mi propio código; Supuse erróneamente que una variable no inicializada estaría vacía y me desconcertó cuando una != 0 la comparación resultó verdadera. Desde entonces, he agregado indicadores del compilador para tratar las variables no inicializadas como errores para asegurarme de que no volveré a caer en esa trampa.

    –Tom Lint

    28 de noviembre de 2019 a las 12:41

avatar de usuario
Sitesh

En palabras simples, a menos que se asigne/inicialice explícitamente un valor, el unión unipersonal no inicializa la memoria asignada. Esta funcionalidad se puede lograr con std:: optional en c++17.

  • Esa es una respuesta engañosa. La unión con un solo miembro tendrá el mismo tamaño que el miembro. Esta memoria simplemente no se inicializará hasta que se inicialice el miembro.

    – Kirill Dmitrenko

    6 de diciembre de 2019 a las 15:51

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad