Modificando-se dentro do método const por meio de um ponteiro não const para si mesmo
Pergunta
No exemplo a seguir const
objeto pode se modificar através const
método, porque nesse método ele se acessa via non-const
ponteiro.(mesmo programa no ideone)
#include <iostream>
struct Object;
Object * g_pObject;
struct Object
{
Object():m_a(0){}
void ModifySelfViaConstMethod() const
{
g_pObject->m_a = 37;
}
int m_a;
};
int main()
{
Object o;
g_pObject = &o;
const Object & co = o;
std::cout << co.m_a << "\n";
co.ModifySelfViaConstMethod();
std::cout << co.m_a << "\n";
return 0;
}
Não sou muito bom em ler o padrão c++, então pergunto aqui:
O que a norma diz sobre isso?
a)const
método não garante que seu objeto permaneça inalterado quando você faz coisas assim
b) Está bem definido e deve compilar
c) outro?
Solução
O que a norma diz sobre isso?
Diz (parafraseando) que this
tem tipo const Object *
, para que você não possa modificar membros diretamente ou chamar funções de membro não const por meio de this
.Não diz nada sobre o que você pode fazer com quaisquer variáveis globais às quais a função possa ter acesso;ele controla apenas o acesso direto ao objeto no qual a função é chamada.
const
método não garante que seu objeto permaneça inalterado quando você faz coisas assim
Não, não importa.Ele afirma a intenção de que a função não modifique o objeto e fornece alguma proteção contra a quebra acidental dessa intenção.Isso não impede que um programador adequadamente perturbado use const_cast
, ou (como aqui) acoplamento descontrolado por meio de variáveis globais para quebrar a promessa.
Está bem definido isso e deve compilar
Sim. o
não é constante, portanto não há nada que impeça você de usar um ponteiro não const ou fazer referência a ele.O const
na função membro restringe apenas o acesso ao objeto via this
, não para objetos arbitrários por meio de outros ponteiros.
Outras dicas
Quando você declara um const
função, é "para o seu próprio bem".
Em outras palavras, você declara const
porque de acordo com seu design inicial, não é suposto alterar nenhum objeto com o qual será invocado durante o tempo de execução.
Se durante algum momento posterior da implementação desta função você acabar alterando o objeto, o compilador irá "gritar com você", dizendo que está errado.
É claro que o compilador será capaz de identificar tal tentativa, somente quando aplicada em this
.
No exemplo dado, o compilador não consegue identificar o problema porque requer uma comparação entre this
e g_pObject
, e essa comparação só pode ocorrer durante o tempo de execução.
Quando um método é declarado como const
, o compilador garante que a instância apontada pelo this
ponteiro não é modificado.Se você tentar modificar o this
por exemplo, o compilador falhará.No entanto, o compilador não tem como saber que g_pObject
e this
estão realmente apontando para a mesma instância.Isso requer uma comparação em tempo de execução, e nenhum compilador perderá tempo realizando comparações em tempo de execução de cada ponteiro usado dentro de um const
método na eventualidade de que eles poder combinar com o this
ponteiro.Então, se você for modificar um Object
através de um ponteiro externo, você terá que fazer sua própria verificação, por exemplo:
void ModifySelfViaConstMethod() const
{
if (g_pObject != this)
g_pObject->m_a = 37;
}
A constância em C++ é um instrumento de segurança, não de segurança.
O código onde a constância é respeitada provavelmente funcionará conforme o esperado, e todas as tentativas não intencionais de eliminar a constância serão alertadas pelo compilador.
Nos casos em que "sei o que estou fazendo" pode-se encontrar toda a variedade de ferramentas, desde const_cast
operador e mutable
palavra-chave para o elenco banal do estilo C.