variavel - É um ponteiro com o endereço certo e digite ainda um ponteiro válido desde C++ 17?




swap com ponteiros (2)

Esta interpretação desta modificação do direito padrão ou existem outras regras que compensam a supressão desta frase citada?

Sim, esta interpretação está correta. Um ponteiro após o final não é simplesmente convertível para outro valor de ponteiro que aponte para esse endereço.

O novo [basic.compound]/3 diz:

Cada valor do tipo de ponteiro é um dos seguintes:
(3.1) um ponteiro para um objeto ou função (o ponteiro é dito para apontar para o objeto ou função), ou
(3.2) um ponteiro após o final de um objeto ([expr.add]), ou

Aqueles são mutuamente exclusivos. p1+1 é um ponteiro após o final, não um ponteiro para um objeto. p1+1 aponta para um hipotético x[1] de um array de tamanho 1 em p1 , não para p2 . Esses dois objetos não são interconversíveis por ponteiro.

Também temos a nota não normativa:

[Nota: Um ponteiro após o final de um objeto ([expr.add]) não é considerado como apontando para um objeto não relacionado do tipo do objeto que pode estar localizado nesse endereço. [...]

que esclarece a intenção.

Como o TC aponta em vários comentários ( notavelmente este ), este é realmente um caso especial do problema que vem ao tentar implementar o std::vector - que é que [v.data(), v.data() + v.size()) precisa ser um intervalo válido e, ainda assim, o vector não cria um objeto de matriz, de modo que a única aritmética de ponteiros definida iria de qualquer objeto no vetor até passado-fim-de-final de seu tamanho único hipotético. array. Para mais recursos, consulte o CWG 2182 , esta discussão P0593R0 , e duas revisões de um artigo sobre o assunto: P0593R0 e P0593R1 (seção 1.3 especificamente).

(Em referência a esta pergunta e resposta .)

Antes do padrão C ++ 17, a seguinte frase foi incluída em [basic.compound]/3 :

Se um objeto do tipo T está localizado em um endereço A, um ponteiro do tipo c * T * cujo valor é o endereço A é dito apontar para esse objeto, independentemente de como o valor foi obtido.

Mas desde C ++ 17, esta frase foi removed .

Por exemplo, acredito que esta frase tenha feito este código de exemplo definido, e que desde C + + 17 este comportamento seja indefinido:

 alignas(int) unsigned char buffer[2*sizeof(int)];
 auto p1=new(buffer) int{};
 auto p2=new(p1+1) int{};
 *(p1+1)=10;

Antes de C ++ 17, p1+1 mantém o endereço para *p2 e tem o tipo correto, então *(p1+1) é um ponteiro para *p2 . Em C ++ 17 p1+1 é um ponteiro passado-fim , portanto não é um ponteiro para objeto e eu acredito que não é dereferencable.

Esta interpretação desta modificação do direito padrão ou existem outras regras que compensam a supressão da frase citada?


Expandir as respostas dadas aqui é um exemplo do que eu acredito que a redação revisada está excluindo:

Aviso: comportamento indefinido

#include <iostream>
int main() {
    int A[1]{7};
    int B[1]{10};
    bool same{(B)==(A+1)};

    std::cout<<B<< ' '<< A <<' '<<sizeof(*A)<<'\n';
    std::cout<<(same?"same":"not same")<<'\n';
    std::cout<<*(A+1)<<'\n';//!!!!!  
    return 0;
}

Por razões totalmente dependentes da implementação (e frágeis), a saída possível deste programa é:

0x7fff1e4f2a64 0x7fff1e4f2a60 4
same
10

Essa saída mostra que as duas matrizes (nesse caso) são armazenadas na memória, de modo que 'passado o fim' de A acontece de manter o valor do endereço do primeiro elemento de B

A especificação revisada é garantir que, independentemente de A+1 nunca seja um ponteiro válido para B A frase antiga 'independentemente de como o valor é obtido' diz que se 'A + 1' apontar para 'B [0]' então é um ponteiro válido para 'B [0]'. Isso não pode ser bom e certamente nunca é a intenção.





c++17