Pode haver diferentes objetos implícitos com base em uma decisão de tempo de execução posterior no C ++ 20?

11

Esta pergunta refere-se à adição de P0593 ao rascunho C ++ 20 mais recente .

Aqui está o meu exemplo:

#include <cstdlib>
#include <cstdio>

void foo(void *p)
{
    if ( std::getchar() == 'i' )
    {
        *(int *)p = 2;
        std::printf("%d\n", *(int *)p);
    }
    else
    {
        *(float *)p = 2;
        std::printf("%f\n", *(float *)p);
    }
}

int main()
{
    void *a = std::malloc( sizeof(int) + sizeof(float) );
    if ( !a ) return EXIT_FAILURE;

    foo(a);
    // foo(a);    [2]
}

Esse código está bem definido para todas as entradas do rascunho mais recente?

O raciocínio expresso em P0593 deixa bastante claro que o descomentário [2]levaria a um comportamento indefinido devido a uma violação estrita do alias, se os dois itens de entrada do usuário diferirem. A criação implícita de objetos deve acontecer apenas uma vez, no ponto de malloc; não é acionado pela declaração de atribuição em foo.

Para qualquer execução real do programa, existe um membro do conjunto não especificado de objetos implícitos que tornaria o programa bem definido. Mas não está claro para mim se a escolha da criação implícita de objetos mencionada em [intro.object] / 10 deve ser feita quando isso mallocacontecer; ou se a decisão pode "viajar no tempo".

O mesmo problema pode surgir para um programa que lê um blob binário em um buffer e, em seguida, toma uma decisão em tempo de execução de como acessá-lo (por exemplo, desserialização; e o cabeçalho nos diz se um float ou int está chegando).

MILÍMETROS
fonte

Respostas:

9

A criação implícita de objetos deve acontecer apenas uma vez, no ponto de malloc; não é acionado pela declaração de atribuição em foo.

Isso não é relevante. O que importa é qual objeto é criado. O padrão diz que o objeto que é criado é aquele que transforma algo que teria sido UB em código bem definido:

essa operação cria e inicia implicitamente o tempo de vida de zero ou mais objetos de tipos de tempo de vida implícito ([basic.types]) em sua região especificada de armazenamento, se isso resultasse no comportamento definido do programa.

O comportamento é basicamente baseado na execução do tempo de execução, não na análise estática. Portanto, você só precisa seguir a execução do programa até encontrar um caso em que o comportamento não seria definido, mas seria definido se um objeto de algum tipo tivesse sido criado nesse armazenamento no momento da operação em questão.

Portanto, o local da criação é sempre "a operação", mas a determinação do que é criado é baseada em como a memória é usada no tempo de execução (ou seja: comportamento).

Nicol Bolas
fonte
2
Para ser claro, você está dizendo que meu código está bem definido?
MM
2
@ MM: Isso está correto.
Nicol Bolas 11/03