Considerar
int main()
{
auto a = new int[0];
delete[] a; // So there's no memory leak
}
Entre a inicialização e a exclusão da cópia, você pode ler o ponteiro em a + 1
?
Além disso, o idioma permite que o compilador seja definido a
como nullptr
?
c++
language-lawyer
Bathsheba
fonte
fonte
a
com certeza (certamente não pode desreferê-lo).a + 1
", o código a seguir é umauto b = a + 1;
comportamento indefinido? (Eu acho que é).0
é realmente o resultado de alguma expressão que você não saberá até o tempo de execução. Comonew int[0]
é seguro, pode poupar a preocupação com alguns casos especiais / ramificações. Imagine se eu fosse inicializar umstd::vector
comstd::vector<int> v(0);
.Respostas:
De acordo com [basic.compound.3] , o valor armazenado em
a
deve ser um dos seguintes:int
)Podemos descartar a primeira possibilidade, pois não havia objetos do tipo
int
construídos. A terceira possibilidade é descartada, pois o C ++ exige que um ponteiro não nulo seja retornado (consulte [basic.stc.dynamic.allocation.2] ). Assim, temos duas possibilidades: um ponteiro após o final de um objeto ou um ponteiro inválido.Eu estaria inclinado a ver
a
como um ponteiro do passado, mas não tenho uma referência respeitável para estabelecer isso definitivamente. (Há, no entanto, uma forte implicação disso em [basic.stc] , vendo como você pode usardelete
esse ponteiro.) Portanto, vou apresentar as duas possibilidades nesta resposta.O comportamento é indefinido, conforme ditado por [expr.add.4] , independentemente de qual possibilidade acima se aplique.
Se
a
for um ponteiro passado-final, é considerado apontar para o elemento hipotético no índice0
de uma matriz sem elementos. Adicionar o número inteiroj
aa
é definido apenas quando0≤0+j≤n
, onden
é o tamanho da matriz. No nosso caso,n
é zero, então a somaa+j
é definida apenas quandoj
é0
. Em particular, a adição1
é indefinida.Se
a
for inválido, cairemos claramente em "Caso contrário, o comportamento será indefinido". (Não é de surpreender que os casos definidos abranjam apenas valores válidos de ponteiro.)Não. Do [basic.stc.dynamic.allocation.2] mencionado acima : "Se a solicitação for bem-sucedida, o valor retornado por uma função de alocação substituível é um valor de ponteiro não nulo" . Há também uma nota de rodapé destacando que o C ++ (mas não C) requer um ponteiro não nulo em resposta a uma solicitação zero.
fonte
De acordo com a recente discussão do refletor do CWG como resultado da edição editorial 3178 ,
new int[0]
produz o que atualmente é chamado de valor do ponteiro "passado-o-fim" .Daqui resulta que
a
não pode ser nulo ea + 1
é indefinido por [expr.add] / 4 .fonte
new int[0]
produz o que atualmente é chamado de valor do ponteiro" passado-o-fim "" Isso não é exato. Não houve muita discussão. Uma pessoa sugeriu que o valor deveria ser "ponteiro após o final de um objeto", e essa declaração foi questionada porque, no caso de uma matriz com0
elementos, não há objeto para o qual terminar após o final.a + 1
é indefinido em qualquer caso, então seu argumento diz respeito apenas à possibilidade dea
ser nulo?a + 1
é indefinido e talvez o valor resultante do ponteiro seja chamado de "ponteiro após o fim". Não estou dizendo que a resposta está errada. É um pouco impreciso, porque poderia ser entendido como uma longa discussão com um consenso que apenas especificando que o resultado é "apontador para o final" é suficiente para resolver o problema. O problema com "ponteiro após o fim" é que ele já passou do final de algum objeto e a subtração1
desse valor de ponteiro fornece um ponteiro para o objeto, o que provavelmente não deve ser o caso de matrizes de0
elementos.