const_cast e ub
-
27-09-2019 - |
Pergunta
US $ 5.2.11/7 - [Nota: Dependendo do tipo de objeto, uma operação de gravação através do ponteiro, LValue ou ponteiro para membro de dados resultantes de um const_cast que lança um quadro -const -qual68) poderia produzir comportamento indefinido (7.1.5.1). ] "
As palavras desta seção (C ++ 03) são surpreendentes para mim. O que é surpreendente são duas coisas.
a) Em primeiro lugar, o uso de 'maio'. Por que é 'pode'? Outros lugares do padrão são muito definitivos sobre o comportamento indefinido
b) Por que o lançamento é a constência de um objeto originalmente constante, não imediatamente 'comportamento indefinido'. Por que é necessária uma gravação para o UB ser acionado?
Solução
a) Em primeiro lugar, o uso de 'maio'. Por que é 'pode'? Outros lugares do padrão são muito definitivos sobre o comportamento indefinido
Não olhe muito profundamente para o uso da palavra poderia aqui. O ponto é que, neste caso, eliminar a constência causa comportamento indefinido.
O padrão C ++ usa "May" ou "pode" frequentemente, como em:
1.3.12: comportamento indefinido poderia Também é esperado quando esse padrão internacional omite a descrição de qualquer definição explícita de comportamento.
Ênfase minha. Basicamente, o padrão usa a palavra "maio" como em "é permitido".
b) Por que o lançamento é a constência de um objeto originalmente constante, não imediatamente 'comportamento indefinido'. Por que é necessária uma gravação para o UB ser acionado?
Uma gravação aciona UB porque é possível que os objetos const possam ser armazenados na memória somente leitura em determinadas plataformas.
Outras dicas
Meu entendimento é que será apenas UB se o objeto em questão for fundamentalmente um objeto const, em vez de um ponteiro const ou referência a um objeto que não era originalmente constante.
A idéia é que os dados que são fundamentalmente constantes podem ser carregados em uma parte somente leitura da memória, e escrever para isso simplesmente não vai funcionar. No entanto, é garantido que funcione corretamente se o objeto em questão for fundamentalmente mutável.
Ex:
const int x = 4;
const int *y = x;
*const_cast<int*>(x) = 3; // UB - the pointed-to object may
// be in read-only memory or whatever.
int a = 7;
const int *b = a;
*const_cast<int*>(b) = 6; // Not UB - the pointed-to object is
// fundamentally mutable.
Para um comentário abaixo, porque o código parece terrível nos comentários:
Em §7.1. 5.1/4 do padrão, o exemplo dado é:
int i = 2;
const int * cip; // pointer to const int
cip = &i; // OK: cv-qualified access path to unqualified
...
int* ip;
ip = const_cast <int *>( cip ); // cast needed to convert const int* to int*
*ip = 4; // defined: *ip points to i, a non-const object
Portanto, isso é especificamente permitido.
Para sua primeira pergunta, se algo poderia Produza um comportamento indefinido, então isso não o torna menos indefinido.
Para a segunda parte, eu imagino que seja por razões de interoperabilidade. Por exemplo, C não (ou não, antes de C99) ter um const
Palavra -chave, portanto, se você deseja passar um objeto const para uma função C, a constência teria que ser descartada. Portanto, o padrão C ++ especifica que isso é permitido desde que nenhuma gravação seja realizada. Se a função C for somente leitura, a constência poderá ser descartada com segurança.
Mesmo em C ++, a correção inconsistente ou incompleta também é bastante comum. Então, ocasionalmente, encontramos situações em que temos que expulsar a constância para passar um objeto const para uma função que não modifica seu argumento, mas o leva por não-consagimento.
Eu acreditaria que é porque um const
O objeto pode ser armazenado na memória somente leitura. Assim, escrever para ele pode ter muitos efeitos diferentes: falha do programa, falha de segmentação ou nenhum efeito.