Excluindo um ponteiro para const (T const *)

91

Eu tenho uma pergunta básica sobre os ponteiros const. Não tenho permissão para chamar funções de membro não const usando um ponteiro const. No entanto, tenho permissão para fazer isso em um ponteiro const:

delete p;

Isso chamará o destruidor da classe que, em essência, é um 'método' não const. Por que isso é permitido? É apenas para apoiar isto:

delete this;

Ou tem alguma outra razão?

Naveen
fonte

Respostas:

113

É para apoiar:

// dynamically create object that cannot be changed
const Foo * f = new Foo;

// use const member functions here

// delete it
delete f;

Mas observe que o problema não se limita a objetos criados dinamicamente:

{
 const Foo f;
 // use it
} // destructor called here

Se os destruidores não pudessem ser chamados em objetos const, não poderíamos usar objetos const de forma alguma.

Agnel Kurian
fonte
21
+1 para sua última edição. Acho que esse é o verdadeiro motivo. Chamada automática de destruidor para objeto const - quase o mesmo que delete f; onde f - ponteiro em const.
bayda de
const Foo * fou Foo const * fnão é um ponteiro const para Foo. É pontual para const Foo. Foo * const f é um ponteiro const para Foo.
user11373693
48

Coloque desta forma - se não fosse permitido, não haveria como deletar objetos const sem usar const_cast.

Semanticamente, const é uma indicação de que um objeto deve ser imutável. Isso não significa, entretanto, que o objeto não deva ser excluído.

PaulJWilliams
fonte
3
Destruidores podem transformar objetos de maneiras bastante violentas, então este deve ser um uso estranho da palavra 'imutável' que eu não conhecia ...
DarthGizka
1
@DarthGizka não, destruidores levam você de um estado onde há um objeto para um onde não existe. C ++ não define nenhum método para observar uma "mutação" pós-destruição
Caleth,
@ Caleth: o padrão pode não permitir que você olhe para o objeto depois que seu destruidor foi executado até a conclusão, mas certamente você tem permissão para observar os efeitos colaterais causados ​​pela destruição. Conseqüentemente, as circunstâncias podem ser facilmente arranjadas para tornar observável a mutação do objeto "imutável". Nos Estados Unidos, o assassinato é difícil de processar quando não há corpo, mas ainda é um assassinato (e pode haver outras evidências suficientes para uma condenação). Mesma diferença.
DarthGizka
6

Não tenho permissão para chamar funções de membro não const usando um ponteiro const.

Sim você é.

class Foo
{
public:
  void aNonConstMemberFunction();
};

Foo* const aConstPointer = new Foo;
aConstPointer->aNonConstMemberFunction(); // legal

const Foo* aPointerToConst = new Foo;
aPointerToConst->aNonConstMemberFunction(); // illegal

Você confundiu um ponteiro const para um objeto não const, com um ponteiro não const para um objeto const.

Tendo dito isto,

delete aConstPointer; // legal
delete aPointerToConst; // legal

é legal excluir qualquer um, pelos motivos já expostos nas outras respostas aqui.

Oktalista
fonte
5

Construtores e destruidores não devem ser vistos como 'métodos'. Eles são construções especiais para inicializar e destruir um objeto de uma classe.

'const pointer' é para indicar que o estado do objeto não seria alterado quando as operações são realizadas nele enquanto ele está ativo.

Indy9000
fonte
5

Outra maneira de ver: o significado preciso de um ponteiro const é que você não será capaz de fazer alterações no objeto apontado que seria visível por meio desse ou de qualquer outro ponteiro ou referência ao mesmo objeto. Mas quando um objeto é destruído, todos os outros ponteiros para o endereço anteriormente ocupado pelo objeto agora excluído não são mais ponteiros para esse objeto . Eles armazenam o mesmo endereço, mas esse endereço não é mais o endereço de nenhum objeto (na verdade, ele logo poderá ser reutilizado como o endereço de um objeto diferente).

Essa distinção seria mais óbvia se os ponteiros em C ++ se comportassem como referências fracas, ou seja, assim que o objeto fosse destruído, todos os ponteiros existentes para ele seriam imediatamente definidos como 0. (Esse é o tipo de coisa considerada muito cara em tempo de execução para ser imposta a todos os programas C ++ e, na verdade, é impossível torná-la totalmente confiável.)

ATUALIZAÇÃO : Lendo isto nove anos depois, é um advogado-ish. Agora acho sua reação original compreensível. Não permitir a mutação, mas permitir a destruição, é claramente problemático. O contrato implícito de ponteiros / referências const é que sua existência funcionará como um bloqueio na destruição do objeto de destino, também conhecido como coleta de lixo automática.

A solução usual para isso é usar quase qualquer outra linguagem.

Daniel Earwicker
fonte
Se você não pode destruir coisas apontadas por ponteiros para const, como você lida com o std::unique_ptr<const T>fim da vida?
Caleth,
@Caleth então não haveria solução para isso em C ++. Esse é apenas um exemplo do problema geral: em C ++, o modificador const significa “Você não pode transformar o alvo, exceto em um sentido onde você pode destruí-lo completamente e tornar todas as outras referências a ele inválidas e fontes de comportamento indefinido”. É por isso que acho que esse tipo de pergunta deve servir como um estímulo para considerar outras linguagens. Ele contém buracos UB que não podem ser resolvidos sem uma abordagem básica diferente.
Daniel Earwicker