Por que não excluir define o ponteiro para NULL?

127

Eu sempre me perguntei por que a configuração automática do ponteiro para NULL após excluir não faz parte do padrão. Se isso for resolvido, muitas das falhas devido a um ponteiro inválido não ocorrerão. Mas, tendo dito isso, posso pensar em duas razões pelas quais o padrão restringiria isso:

  1. Atuação:

    Uma instrução adicional pode diminuir o deletedesempenho.

  2. Poderia ser por causa de constindicadores.

    Então, novamente, o padrão poderia ter feito algo para este caso especial, eu acho.

Alguém sabe os motivos exatos para não permitir isso?

aJ.
fonte

Respostas:

150

O próprio Stroustrup responde. Um trecho:

O C ++ permite explicitamente que uma implementação de exclusão zere um operando lvalue, e eu esperava que as implementações fizessem isso, mas essa ideia não parece ter se tornado popular entre os implementadores.

Mas a questão principal que ele levanta é que o argumento de exclusão não precisa ser um valor l.

Dan Olson
fonte
Eu acho que isso poderia usar mais explicações. Eu nem tenho certeza do que ele está dizendo ... Acho que vou ter que voltar mais tarde, quando puder dedicar algumas horas para pesquisar isso até que eu entenda. Ou você pode explicar a resposta para nos ajudar a entender mais rapidamente.
Gabriel Staples
63

Primeiro, definir como nulo exigiria uma variável armazenada na memória. É verdade que você normalmente possui um ponteiro em uma variável, mas às vezes pode querer excluir um objeto em um endereço calculado. Isso seria impossível com a exclusão "anulação".

Depois vem o desempenho. Você pode ter escrito código de forma que o ponteiro fique fora do escopo imediatamente após a exclusão . Preenchê-lo com nulo é apenas uma perda de tempo. E C ++ é uma linguagem com a ideologia "não precisa disso? Então você não precisa pagar por isso".

Se você precisar de segurança, há uma grande variedade de indicadores inteligentes ao seu serviço ou pode escrever por conta própria - melhor e mais inteligente.

dente afiado
fonte
4
Bom ponto wrt calculado endereço, mesmo se é algo que você não vê muitas vezes
snemarch
você está falando de um novo canal quando diz que às vezes pode excluir um objeto em um endereço calculado apenas. ???
destructor
@PravasiMeet Não, quero dizer algo comodelete (ptr + i)
sharptooth
39

Você pode ter vários ponteiros apontando para essa memória. Isso criaria uma falsa sensação de segurança se o ponteiro que você especificou para a exclusão fosse definido como nulo, mas todos os outros ponteiros não. Um ponteiro nada mais é do que um endereço, um número. Também pode ser um int com uma operação de desreferência. O que quero dizer é que você também teria que digitalizar todos os ponteiros para encontrar aqueles que estão referenciando a mesma memória que você acabou de excluir e anulá-los também. Seria computacionalmente intenso varrer todos os ponteiros para esse endereço e anulá-los, porque o idioma não foi projetado para isso. (Embora algumas outras línguas estruturem suas referências para atingir um objetivo semelhante de uma maneira diferente.)

AaronLS
fonte
19

Um ponteiro pode ser salvo em mais de uma variável, definindo um deles como NULL ainda deixaria ponteiros inválidos nas outras variáveis. Portanto, você não ganha muito, é mais provável que crie uma falsa sensação de segurança.

Além disso, você pode criar sua própria função que faz o que você deseja:

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}
sth
fonte
12

Porque não há realmente nenhuma necessidade e porque exigiria excluir o uso de ponteiro para ponteiro, em vez de apenas ponteiro.

snemarch
fonte
verdade, mas que resultaria na mesma sobrecarga
snemarch
7

deleteé usado principalmente em destruidores; nesse caso, definir um membro como NULL não faz sentido. Algumas linhas depois, no fechamento }, o membro não existe mais. Nos operadores de atribuição, uma exclusão geralmente é seguida por uma atribuição de qualquer maneira.

Além disso, tornaria ilegal o seguinte código:

T* const foo = new T;
delete foo;
MSalters
fonte
6

Aqui está outro motivo; suponha que delete defina seu argumento como NULL:

int *foo = new int;
int *bar = foo;
delete foo;

A barra deve ser definida como NULL? Você pode generalizar isso?

SingleNegationElimination
fonte
5

Se você tiver uma matriz de ponteiros e sua segunda ação for excluir a matriz vazia, não há nenhum ponto em que cada valor seja definido como nulo quando a memória estiver prestes a ser liberada. Se você quiser que ele seja nulo .. escreva nulo para ele :)

Conta morta
fonte
4

O C ++ permite que você defina seu próprio operador como novo e exclua para que, por exemplo, eles usem seu próprio alocador de pool. Se você fizer isso, será possível usar new e delete com coisas que não sejam estritamente endereços, mas digam índices em sua matriz de pool. Nesse contexto, o valor de NULL (0) pode ter um significado legal (referindo-se ao primeiro item no pool).
Portanto, excluir o conjunto NULL automaticamente para o seu argumento nem sempre tem o significado de - defina o valor como um valor inválido. O valor inválido nem sempre pode ser NULL.

shoosh
fonte
4

A filosofia do C ++ é "pague apenas se você a usar". Eu acho que pode responder à sua pergunta.

Às vezes, você também pode ter seu próprio heap, que recuperará a memória excluída ... ou, às vezes, o ponteiro que não pertence a nenhuma variável. Ou ponteiro armazenado em poucas variáveis ​​- é possível zerar apenas uma delas.
Como você pode ver, há muitos problemas e possíveis problemas.

bayda
fonte
3

Definir o ponteiro para NULL automaticamente não resolveria a maioria dos problemas com mau uso do ponteiro. A única falha que evitaria é se você tentar excluí-lo duas vezes. E se você chamar uma função de membro nesse ponteiro? Ainda falharia (supondo que ele acesse variáveis ​​de membro). O C ++ não o impede de chamar nenhuma função em ponteiros NULL, nem deve fazê-lo do ponto de vista do desempenho.


fonte
-1

Vejo pessoas dando respostas estranhas a essa pergunta.

ptr = NULL; Como uma declaração tão simples pode causar atraso no desempenho?

Outra resposta está dizendo que podemos ter vários ponteiros apontando para o mesmo local de memória. Certamente podemos. Nesse caso, a operação de exclusão em um ponteiro tornaria apenas o ponteiro NULL (se a exclusão estivesse tornando o ponteiro NULL) e o outro ponteiro não seria NULL e apontaria para o local da memória livre.

A solução para isso deveria ter sido o usuário excluir todos os ponteiros apontando para o mesmo local. Internamente, ele deve verificar se a memória já está liberada ou não liberada. Somente faça o ponteiro NULL.

Stroustrup poderia ter projetado excluir para funcionar dessa maneira. Ele pensou que os programadores cuidariam disso. Então ele ignorou.

Nimesh Bapodra
fonte