Criação de objeto implícito não especificado

9

Como a criação implícita de objetos P0593 para manipulação de objetos de baixo nível foi aceita, agora os objetos podem ser criados implicitamente no C ++ 20.

Especificamente, o texto introduzido pela proposta permite que certas operações (como std::malloc) criem e iniciem automaticamente a vida útil de objetos de certos tipos, os chamados tipos de vida implícita , se a introdução de tais objetos fizer com que um programa com comportamento indefinido tenha comportamento definido. Veja [intro.object] / 10 .

O rascunho agora afirma ainda que, se houver vários conjuntos desses objetos que possam ser criados implicitamente para fornecer ao programa o comportamento definido, não será especificado qual desses conjuntos será criado. (A frase relevante parece não estar presente na última revisão da proposta que eu pude acessar, R5, mas está no rascunho do commit.)

Existe realmente um programa para o qual essa escolha do conjunto de objetos criado implicitamente é observável? Em outras palavras, existe um programa com comportamento definido, mas não especificado, por meio dessa nova regra, de modo que é possível inferir a partir da saída que conjuntos de tipos de objetos implícitos (dentre mais de um possível) foram criados?

Ou essa frase foi apenas para esclarecer a execução do programa na máquina abstrata (sem impacto observável)?

noz
fonte
2
(OT) se um objeto criado implicitamente é um int, podemos chamá-lo de "int implícito"?
MM
Parece incerto se a escolha do elemento do conjunto não especificado deve ser conhecida no ponto do malloc
MM
@MM Supus que a escolha do conjunto fosse considerada abstrata como uma escolha única para toda a execução do programa fora do fluxo de execução, mas com a criação acontecendo diretamente na operação em questão (ie std::malloc), caso contrário, você terá problemas com a definição sendo recursivamente dependendo do futuro.
noz
Fiz outra pergunta sobre esse tópico, stackoverflow.com/questions/60627249 . Claro que mais alguns corolários vêm à mente, mas uma pergunta de cada vez.
MM
A proposta afirma que é impossível distinguir isso, o que é importante, pois não há como a escolha ser feita “corretamente”, apenas otimizações para evitar que de outra forma seriam ( muito estritamente) válidas.
Davis Herring

Respostas:

9

Vamos pegar o exemplo no padrão e alterá-lo um pouco:

#include <cstdlib>
struct X { int a, b; };
X *make_x() {
  // The call to std::malloc implicitly creates an object of type X
  // and its subobjects a and b, and returns a pointer to that X object
  // (or an object that is pointer-interconvertible ([basic.compound]) with it),
  // in order to give the subsequent class member access operations
  // defined behavior.
  X *p = (X*)std::malloc(sizeof(struct X) * 2); // me: added the *2
  p->a = 1;
  p->b = 2;
  return p;
}

Anteriormente, havia apenas um conjunto de objetos válidos que podiam ser criados implicitamente nesse armazenamento - tinha que ser exatamente um X. Mas agora, temos armazenamento para dois Xs, mas gravamos apenas em um deles, e nada neste programa toca o restante dos bytes. Portanto, existem muitos conjuntos diferentes de objetos que podem ser criados implicitamente - talvez dois Xs, talvez um Xe dois ints, talvez um Xe oito chars, ...

Não é observável qual conjunto é criado, porque, se houvesse alguma observação real, isso reduziria as possibilidades apenas aos conjuntos válidos. Se fizermos algo assim p[1]->a = 3, o universo de possibilidades desmorona para apenas aquele com dois Xs.

Em outras palavras, vários conjuntos de objetos criados implicitamente são possíveis apenas quando não há observações suficientes no programa para distinguir sua validade. Se houvesse uma maneira de distinguir, então, por definição, eles não seriam todos válidos.

Barry
fonte
Este é apenas o meu palpite de qualquer maneira.
Barry
Por isso, entendo que simplesmente não há como distinguir / observar a existência ou a não existência de objetos de diferentes tipos de vida implícita sem comportamento indefinido. Nesse caso, parece-me que é o único uso de " comportamento não especificado " no padrão que não pode realmente levar a diferentes resultados observáveis.
noz
11
Ou que se os únicos acessos são via glvalues do tipo [cv] char, unsigned charou std::byte? Um objeto de qualquer tipo trivialmente copiável também poderia existir lá, eu acho?
aschepler
2
Mesmo no exemplo original, também é possível criar um objeto de matriz junto com o único Xobjeto.
TC