Os destruidores triviais causam o aliasing

C ++ 11 §3.8.1 declara que, para um objeto com um destruidor trivial, posso terminar sua vida útil atribuindo ao seu armazenamento. Eu estou querendo saber se destruidores triviais podem prolongar a vida útil do objeto e causar problemas de aliasing por "destruir um objeto" que eu terminei a vida útil de muito mais cedo.

Para começar, algo que eu sei é seguro e alias-free

void* mem = malloc(sizeof(int));
int*  asInt = (int*)mem;
*asInt = 1; // the object '1' is now alive, trivial constructor + assignment
short*  asShort = (short*)mem;
*asShort = 2; // the object '1' ends its life, because I reassigned to its storage
              // the object '2' is now alive, trivial constructor + assignment
free(mem);    // the object '2' ends its life because its storage was released

Agora, para algo que não é tão claro:

{
    int asInt = 3; // the object '3' is now alive, trivial constructor + assignment
    short* asShort = (short*)&asInt; // just creating a pointer
    *asShort = 4; // the object '3' ends its life, because I reassigned to its storage
                  // the object '4' is now alive, trivial constructor + assignment
    // implicitly, asInt->~int() gets called here, as a trivial destructor
}   // 'the object '4' ends its life, because its storage was released

§6.7.2 afirma que objetos de duração de armazenamento automático são destruídos no final do escopo, indicando que o destruidor é chamado.Se houver um int para destruir,*asShort = 2 é uma violação de aliasing porque estou desreferenciando um ponteiro de tipo não relacionado. Mas se a duração do inteiro terminar antes*asShort = 2, então eu estou chamando um destruidor int em um curto.

Eu vejo várias seções concorrentes sobre isso:

§ 3.8.8 lê

Se um programa terminar o tempo de vida de um objeto do tipo T com duração de armazenamento estática (3.7.1), thread (3.7.2) ou automática (3.7.3) e se T tiver um destruidor não-trivial, 39 o programa deve garantir que um objeto do tipo original ocupe o mesmo local de armazenamento quando a chamada implícita do destruidor ocorrer; caso contrário, o comportamento do programa é indefinido.

O fato de eles chamarem tipos T com um destruidor não-trivial como um comportamento indefinido parece, para mim, indicar que ter um tipo diferente naquele local de armazenamento com um destruidor trivialé definido, mas não consegui encontrar em nenhum lugar na especificação que definiu isso.

Tal definição seria fácil se um destruidor trivial fosse definido como noop, mas há pouquíssimas especificações sobre eles.

§6.7.3 indica que os goto's podem entrar e sair de escopos cujas variáveis ​​possuem construtores triviais e destruidores triviais. Isso parece sugerir um padrão em que os destruidores triviais podem ser ignorados, mas a seção anterior da especificação sobre a destruição de objetos no final do escopo não menciona nada disso.

Finalmente, há a leitura atrevida:

§3.8.1 indica que tenho permissão para iniciar a vida útil de um objeto sempre que eu quiser, se seu construtor for trivial. Isso parece indicar que eu poderia fazer algo como

{
    int asInt = 3;
    short* asShort = (short*)&asInt;
    *asShort = 4; // the object '4' is now alive, trivial constructor + assignment
    // I declare that an object in the storage of &asInt of type int is
    // created with an undefined value.  Doing so reuses the space of
    // the object '4', ending its life.

    // implicitly, asInt->~int() gets called here, as a trivial destructor
}

A única dessas leituras que parece sugerir qualquer problema de aliasing é, por si só, o §6.7.2. Parece que, quando lida como parte de uma especificação inteira, o destruidor trivial não deve afetar o programa de qualquer forma (embora por várias razões). Alguém sabe o que acontece nessa situação?

questionAnswers(2)

yourAnswerToTheQuestion