Como o Heap Obras em C ++
o montão
Menu
Assim como é possível passar um ponteiro para uma função, é possível para uma função para devolver um apontador. Uma função que retorna o endereço de um duplo é declarado como segue:
double * fn (void) -
No entanto, você deve ter muito cuidado ao retornar um ponteiro. Para entender os perigos, você deve saber algo sobre o escopo de variáveis.
alcance limitado em C ++
Slidar é a faixa sobre a qual uma variável é definida. Considere o seguinte trecho de código:
// A seguinte variável é acessível para // todas as funções e definida, enquanto o programa está sendo executado // (escopo global) int intGlobal - // o seguinte intChild variável é acessível // apenas para a função e só é definida // enquanto C ++ é criança execução () ou uma função // qual criança () chama (escopo de função) criança (void) {int intChild -} // o seguinte intParent variável tem a função // pai scopevoid (void) {int intParent = 0-child () - int intLater = 0-intParent = intLater-} int main (int nargs, char * pArgs []) {parent () -}
Este fragmento programa começa com a declaração de uma variável intGlobal. Esta variável existe a partir do momento em que o programa começa a executar até que ele termine. Você diz que intGlobal # 147 tem escopo do programa. # 148- Você também dizer que a variável # 147 entra no âmbito # 148- antes mesmo da função a Principal() é chamado.
A função a Principal() invoca imediatamente parent (). A primeira coisa que o processador vê em parent () é a declaração de intParent. Nesse ponto, intParent entra no âmbito de aplicação - isto é, intParent é definido e disponível para o restante da função parent ().
A segunda declaração em parent () é a chamada para criança(). Mais uma vez, a função criança() declara uma variável local, desta vez intChild. O âmbito da variável intChild está limitado à função criança(). tecnicamente, intParent não é definido no âmbito da criança() Porque criança() não têm acesso a intParent- No entanto, a variável intParent continua a existir enquanto criança() é execução.
Quando criança() saídas, a variável intChild sai do escopo. Não só é intChild não acessível, não existe mais. (A memória ocupado por intChild é retornado para a piscina geral a ser utilizado para outras coisas.)
Como parent () continua a execução, a variável intLater entra no âmbito da declaração. No ponto em que parent () retorna ao a Principal(), ambos intParent e intLater ir fora do escopo.
Porque intGlobal é declarado globalmente, neste exemplo, está disponível para todas as três funções e permanece disponível para a vida do programa.
Examinando o problema escopo no C ++
O segmento de código a seguir compila sem erro, mas não funciona (não é apenas odeio isso?):
double * criança (void) {dLocalVariable-devolver em dobro dLocalVariable-} pai (void) {double * pdLocal-pdLocal = child () - * pdLocal = 1.0-}
O problema com isto é que a função dLocalVariable é definido apenas no âmbito da função criança(). Assim, no momento em que o endereço de memória dLocalVariable é devolvido a partir criança(), refere-se a uma variável que não existe mais. A memória dLocalVariable anteriormente ocupado provavelmente está sendo usado para outra coisa.
Este erro é muito comum, porque podem surgir em um número de maneiras. Infelizmente, esse erro não causar o programa para parar instantaneamente. Na verdade, o programa pode funcionar bem na maior parte do tempo - isto é, o programa continua a funcionar enquanto a memória ocupada anteriormente pela dLocalVariable não é reutilizado imediatamente. Tais problemas intermitentes são os mais difíceis de resolver.
Fornecendo uma solução usando o heap em C ++
O problema âmbito originou porque C ++ levou de volta a memória definido localmente antes de o programador estava pronto. O que é necessário é um bloco de memória controlado pelo programador. Ela pode alocar a memória e colocá-lo de volta quando ela quer - não porque C ++ acha que é uma boa ideia. Tal bloco de memória é chamado o heap.
memória heap é alocado usando o novo palavra-chave seguido pelo tipo de objeto para alocar. o novo comando quebra um pedaço de memória fora do heap grande o suficiente para segurar o tipo especificado de objeto e retorna o seu endereço. Por exemplo, o seguinte aloca um duplo variável fora da pilha:
double * criança (void) {double * pdLocalVariable = new double-retorno pdLocalVariable-}
Esta função agora funciona corretamente. Embora a variável pdLocalVariable sai do escopo quando a função criança() retornos, a memória para o qual pdLocalVariable refere-se não faz. Uma localização de memória retornado pela novo não sai do âmbito de aplicação até que seja explicitamente voltou para a pilha usando a palavra-chave excluir, que é especificamente projetado para essa finalidade:
pai (void) {// child () retorna o endereço de um bloco de // da memorydouble heap * pdMyDouble = child () - // armazenar um valor lá * pdMyDouble = 1,1 - // ... // agora devolver o memória para o heapdelete pdMyDouble-pdMyDouble = 0 - // ...}
Aqui, o ponteiro retornado por criança() é usado para armazenar um valor duplo. Depois a função é terminado com a localização de memória, que é devolvido para a pilha. A função parent () define o ponteiro para 0 depois que a memória heap foi devolvido - este não é um requisito, mas é uma idéia muito boa.
Se o programador erroneamente tenta armazenar em algo * pdMyDouble depois de excluir, o programa irá falhar imediatamente com uma mensagem de erro significativa.
Você pode usar novo para alocar matrizes da pilha, bem como, mas você deve retornar um array utilizando o excluir[] palavra-chave:
int * nArray = new int [10] -nArray [0] = 0-delete [] nArray-
tecnicamente new int [10] invoca o novo[] operador mas funciona da mesma forma novo.