A confusão é que C permite explicitamente punções de tipo por meio de uma união, enquanto C ++ (c ++ 11) não tem essa permissão.
c11
6.5.2.3 Estrutura e membros do sindicato
95) Se o membro usado para ler o conteúdo de um objeto de união não for o mesmo que o membro usado pela última vez para armazenar um valor no objeto, a parte apropriada da representação do objeto será reinterpretada como uma representação de objeto no novo digite como descrito em 6.2.6 (um processo às vezes chamado de '' punção de tipo ''). Esta pode ser uma representação de interceptação.
A situação com C ++:
c ++ 11
9.5 Sindicatos [class.union]
Em uma união, no máximo um dos membros de dados não estáticos pode estar ativo a qualquer momento, ou seja, o valor de no máximo um dos membros de dados não estáticos pode ser armazenado em uma união a qualquer momento.
O C ++ posteriormente possui uma linguagem que permite o uso de uniões contendo struct
s com seqüências iniciais comuns; no entanto, isso não permite punição de tipo.
Para determinar se a punção de tipo de união é permitida em C ++, precisamos procurar mais. Lembre-se quec99 é uma referência normativa para C ++ 11 (e C99 possui linguagem semelhante à C11, permitindo punção de tipo de união):
3.9 Tipos [basic.types]
4 - A representação do objeto de um objeto do tipo T é a sequência de N objetos de caracteres não assinados capturados pelo objeto do tipo T, onde N é igual a sizeof (T). A representação do valor de um objeto é o conjunto de bits que contém o valor do tipo T. Para tipos trivialmente copiáveis, a representação do valor é um conjunto de bits na representação do objeto que determina um valor, que é um elemento discreto de uma implementação. conjunto de valores definido. 42
42) A intenção é que o modelo de memória do C ++ seja compatível com o da linguagem de programação C. ISO / IEC 9899
Fica particularmente interessante quando lemos
3.8 Duração do objeto [basic.life]
A vida útil de um objeto do tipo T começa quando: - é obtido o armazenamento com o alinhamento e tamanho adequados para o tipo T e - se o objeto tiver uma inicialização não trivial, sua inicialização estará concluída.
Portanto, para um tipo primitivo (cujo ipso facto possui inicialização trivial) contido em uma união, o tempo de vida do objeto abrange pelo menos o tempo de vida da própria união. Isso nos permite invocar
3.9.2 Tipos de compostos [basic.compound]
Se um objeto do tipo T estiver localizado no endereço A, diz-se que um ponteiro do tipo cv T *, cujo valor é o endereço A, aponte para esse objeto, independentemente de como o valor foi obtido.
Supondo que a operação na qual estamos interessados seja punitiva, ou seja, assumindo o valor de um membro do sindicato não ativo, e dado acima, que temos uma referência válida ao objeto referido por esse membro, essa operação é lvalue-to -rvalue conversion:
4.1 Conversão de valor em valor [conv.lval]
Um glvalue de um tipo sem função e sem matriz T
pode ser convertido em um prvalor. Se T
é um tipo incompleto, um programa que requer essa conversão está mal formado. Se o objeto ao qual o glvalue se refere não é um objeto do tipo T
e não é um objeto de um tipo derivado T
, ou se o objeto não for inicializado, um programa que necessite dessa conversão terá um comportamento indefinido.
A questão então é se um objeto que é um membro da união não ativo é inicializado por armazenamento no membro da união ativo. Tanto quanto posso dizer, este não é o caso e, portanto, se:
- uma união é copiada no
char
armazenamento e retorno da matriz (3.9: 2) ou
- uma união é copiada em sentido inverso para outra união do mesmo tipo (3.9: 3), ou
- uma união é acessada através dos limites do idioma por um elemento do programa em conformidade com a ISO / IEC 9899 (na medida em que seja definido) (3.9: 4, nota 42);
o acesso a uma união por um membro não ativo é definido e segue a representação de objeto e valor; o acesso sem uma das interposições acima é um comportamento indefinido. Isso tem implicações para as otimizações permitidas a serem executadas em um programa desse tipo, pois a implementação pode, é claro, presumir que um comportamento indefinido não ocorra.
Ou seja, embora possamos legitimamente formar um valor mínimo para um membro do sindicato não ativo (é por isso que atribuir a um membro não ativo sem construção é aceitável), ele é considerado não inicializado.