Um aplicativo de teste simples:
cout << new int[0] << endl;
saídas:
0x876c0b8
Então parece que funciona. O que o padrão diz sobre isso? É sempre legal "alocar" um bloco vazio de memória?
Um aplicativo de teste simples:
cout << new int[0] << endl;
saídas:
0x876c0b8
Então parece que funciona. O que o padrão diz sobre isso? É sempre legal "alocar" um bloco vazio de memória?
Respostas:
A partir de 5.3.4 / 7
Quando o valor da expressão em um novo declarador direto é zero, a função de alocação é chamada para alocar uma matriz sem elementos.
From 3.7.3.1/2
O efeito de desreferenciar um ponteiro retornado como uma solicitação para tamanho zero é indefinido.
Além disso
Mesmo se o tamanho do espaço solicitado [por novo] for zero, a solicitação poderá falhar.
Isso significa que você pode fazê-lo, mas não pode legalmente (de uma maneira bem definida em todas as plataformas) desreferenciar a memória que obtém - você só pode transmiti-la para excluir a matriz - e deve excluí-la.
Aqui está uma nota de rodapé interessante (isto é, não uma parte normativa do padrão, mas incluída para fins de exposição) anexada à frase de 3.7.3.1/2
[32 A intenção é ter o operador new () implementável chamando malloc () ou calloc (), para que as regras sejam substancialmente as mesmas. C ++ difere de C ao exigir uma solicitação zero para retornar um ponteiro não nulo.]
new[]
com um delete[]
- qualquer que seja o tamanho. Em particular, quando você chamar new[i]
você precisa de um pouco mais de memória do que o que você está tentando alloc, a fim de armazenar o tamanho da matriz (que é usado mais tarde por delete[]
quando desalocá)
Sim, é legal alocar uma matriz de tamanho zero como esta. Mas você também deve excluí-lo.
int ar[0];
é ilegal, por que tudo bem?
sizeof (type)
é esperado que nunca retorne zero. Veja por exemplo: stackoverflow.com/questions/2632021/can-sizeof-return-0-zero
O que o padrão diz sobre isso? É sempre legal "alocar" um bloco vazio de memória?
Todo objeto tem uma identidade única, ou seja, um endereço exclusivo, o que implica um comprimento diferente de zero (a quantidade real de memória será aumentada silenciosamente, se você solicitar zero bytes).
Se você alocasse mais de um desses objetos, descobriria que eles têm endereços diferentes.
operator []
também armazena o tamanho da matriz em algum lugar (consulte isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array ). Portanto, se a implementação alocar a contagem de bytes com os dados, ela poderá alocar a contagem de bytes e 0 bytes para os dados, retornando o ponteiro 1-passado-último.
operator new[]
devem retornar indicadores diferentes. Entre, new expression
há algumas regras adicionais (5.3.4). Não consegui encontrar nenhuma pista de que, new
com tamanho 0, seja realmente necessário para alocar qualquer coisa. Desculpe, diminuí a votação porque acho que sua resposta não está respondendo às perguntas, mas está fornecendo algumas declarações controversas.
new[]
implementação para retornar endereços em uma faixa onde não há memória dinâmica mapeada, portanto, não realmente usando qualquer memória (ao usar espaço de endereço)
while(!exitRequested) { char *p = new char[0]; delete [] p; }
loop sem reciclar ponteiros entraria em pó antes que pudesse ficar sem espaço de endereço, mas em uma plataforma com ponteiros de 32 bits, seria suposição muito menos razoável.
Sim, é totalmente legal alocar um 0
bloco de tamanho new
. Você simplesmente não pode fazer nada útil com ele, pois não há dados válidos para você acessar. int[0] = 5;
é ilegal.
No entanto, acredito que o padrão permite coisas como malloc(0)
retornar NULL
.
Você ainda precisará de delete []
qualquer ponteiro que voltar da alocação.
Curiosamente, o C ++ exige que o operador retorne um ponteiro legítimo mesmo quando zero bytes são solicitados. (Exigir esse comportamento estranho simplifica as coisas em outras partes do idioma.)
Eu encontrei o Effective C ++ Third Edition dito assim no "Item 51: Aderir à convenção ao escrever novo e excluir".
Eu garanto a você que o novo int [0] lhe custa espaço extra desde que eu o testei.
Por exemplo, o uso de memória de
int **arr = new int*[1000000000];
é significativamente menor que
int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
arr[i]=new int[0];
}
O uso de memória do segundo trecho de código menos o do primeiro trecho de código é a memória usada para os numerosos novos int [0].