• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

magician

Stack vs Heap

23 mensagens neste tópico

Boas tenho andado a ver algumas coisas em C++ a linguagem que dizia não ter intenções de aprender lol

E surgiu-me uma questão!

É possível criar objectos de duas maneiras, ou chamando o método construtor

Objecto obj (arg1, arg2);

ou de forma dinâmica

Objecto *obj = new Objecto(arg1, arg2);

O primeiro exemplo faz a alocação na stack memorie e o segundo faz a heap memorie! Pessoalmente prefiro a segunda forma lol faz-me lembrar Java e C# xD mas não quero assassinar a linguagem só por gostar mais daquela forma.

Quando usar um ou outro ? efeitos a nível de performance o que se recomenda ?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Alocações na stack são por norma muito mais rápidas que alocações no heap. Por isso se tens um loop por exemplo e tens de criar montes de objectos temporários, alocar na stack é uma melhor opção. Se por outro lado precisas de criar objectos para ser usados durante toda a execução do programa e precisas de passar ponteiros desses objectos para outras funções, então deves usar a heap. Objectos na stack funcionam da mesma maneira que variáveis locais em C, não podes passar endereços deles para outras funções porque quando essa função termina, o endereço deixa de fazer sentido, ou seja, têm a duração da função onde são alocados. A única "excepção" é a função main, pois quando acaba o programa também acaba. :(

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ou seja de forma resumida stack para objecto temporários, e heap para objecto com maior período de utilidade dai também ter o delete para quando não são precisos serem apagados.

Mas posso usar objectos na heap sempre que queira certo? tenho é depois de ter o cuidado de os "destruir" quando não precisar mais deles.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ou seja de forma resumida stack para objecto temporários, e heap para objecto com maior período de utilidade dai também ter o delete para quando não são precisos serem apagados.

Mas posso usar objectos na heap sempre que queira certo? tenho é depois de ter o cuidado de os "destruir" quando não precisar mais deles.

Sim, é isso.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

não podes passar endereços deles para outras funções porque quando essa função termina, o endereço deixa de fazer sentido, ou seja, têm a duração da função onde são alocados. A única "excepção" é a função main, pois quando acaba o programa também acaba. :)

Não deves passar o endereço do objecto "para trás", isto é, não deves retornar o endereço ou passá-lo num parâmetro de saída, nem passá-los a outras threads.

Mas passar o endereço de uma variável local numa chamada a outra função, não há problema, pois a "função-mãe" :( só retornará depois de a função chamada retornar, e igualmente o espaço só será "libertado" depois do retorno dessa função chamada.

Bah, ficou confuso. Exemplos:

int *retorna_apontador(int i) {
    int x=i;
    return &x; // <- mau! retorna o endereço de uma variável local. costuma dar warning
}

int *retorna_apontador(int *i) {
    int *x = new int;
    *x = *i;
    return x; // <- código ok, mas não esquecer de fazer posteriormente o delete
}

void funcao_mae() {
    int x=10;
    int *pi = retorna_apontador(&x); // <- ok, passar endereço de variável local "para baixo"

    // utilizar pi

    delete pi;
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sim para além disso podes também passar os objectos por referencia, é mais rápido e permite alterar o conteúdo do objecto mesmo estando em níveis independentes.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sim, TheDark, não expliquei bem esse conceito. :(

Sim para além disso podes também passar os objectos por referencia, é mais rápido e permite alterar o conteúdo do objecto mesmo estando em níveis independentes.

Não é mais rápido. A velocidade é a mesma, e as limitações são as mesmas. É apenas "açúcar sintáctico" no compilador.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sim, TheDark, não expliquei bem esse conceito. :(

Não é mais rápido. A velocidade é a mesma, e as limitações são as mesmas. É apenas "açúcar sintáctico" no compilador.

Não é mesmo mais rápido do que passar por valor, por por valor é feita uma copia do objecto e é essa copia que é enviada para dentro da função. por referencia envias o endereço do objecto e não é preciso criar uma copia do mesmo logo ganhas performance embora isso não que dizer que só se deva usar passagem por referencia.!

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não é mesmo mais rápido do que passar por valor, por por valor é feita uma copia do objecto e é essa copia que é enviada para dentro da função. por referencia envias o endereço do objecto e não é preciso criar uma copia do mesmo logo ganhas performance embora isso não que dizer que só se deva usar passagem por referencia.!

Em C++ tens a distinção entre passar por referência e por ponteiro, era a essa comparação que me referia, em nenhum lado do tópico falamos em passagem de objectos por valor. :(

E mesmo assim acho que depende do tipo de dados que estás a passar, não sei se em todos os casos é a forma mais eficiente.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Em C++ tens a distinção entre passar por referência e por ponteiro, era a essa comparação que me referia, em nenhum lado do post falamos em passagem de objectos por valor. :(

E mesmo assim acho que depende do tipo de dados que estás a passar, não sei se em todos os casos é a forma mais eficiente.

Sim entre ponteiro e referencia deve ser ela por ela. Por valor acho que objectos pequenos, tipos primitivos não deve compensar muito agora objectos "grandes" ou que queremos alterar o seu conteúdo a passagem por ref é bastante vantajosa.

Por exemplo ligações a BD, streams etc...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

A passagem 'por valor' é na verdade uma passagem por cópia, e deve ser utilizada sempre que pretendes criar uma cópia do parâmetro, seja qual for a tua razão para isso.

Quanto ao assunto do tópico inicial, a primeira instrução reserva espaço na memória para o objecto, a segunda só cria um ponteiro para uma localização distante para onde irá o teu objecto.

Se souberes quanto espaço vais usar não tens razão nenhuma para não usar  a primeira opção, se não souberes tens forçosamente que usar a segunda pois não tens outra hipótese.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Qualquer uma das duas instanciaçoes, como variável local e no heap, reservam espaço de memória.

Se souberem como funciona uma pilha (stack) e o heap, estarão sempre à vontade com "scope" de variáveis em qualquer linguagem.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Qualquer uma das duas instanciaçoes, como variável local e no heap, reservam espaço de memória.

O segundo método não. Só cria um ponteiro para um local livre, e quando esse espaço acabar é procurado outro e por aí adiante. O primeiro método pega num espaço e reserva-o para todos os efeitos, não é utilizado para mas nada e a aplicação  só tem aquele espaço de tamanho fixo.

Usando o primeiro método, se por algum motivo não houver espaço a aplicação é terminada de imadiato, usando o segundo, terás um erro assim que houver falta de espaço, quando o estiveres a utilizar.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Em ambos os métodos há alocação de espaço, embora essa alocação seja de forma diferente. Inclusivé, em ambos os métodos o mesmo espaço "fisico" de memória será muito provavelmente utilizado por diferentes variáveis durante o decorrer do programa (em pontos exclusivos no tempo, claro). Esse "local livre" como tu lhe chamas é procurado por um algoritmo no momento da instanciação da classe, e o espaço encontrado é reservado para o objecto, até que seja libertado explicitamente.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não o Njay tem razão o new é equivalente ao malloc do C aloca X espaço de memoria dinamicamente. O primeiro método aloca espaço estático, se for preciso mais memoria do que a alocada rebente xD

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O espaço na pilha não é própriamente um espaço estático, antes pelo contrário. É temporário e dinâmico, embora não tão dinâmico como o espaço no heap. Se ficares sem espaço na pilha o programa normalmente rebenta mas não necessariamente, depende do sistema operativo, do compilador/opções do compilador, processador.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O sistema operativo pode até, quando tentas aceder fora da zona da stack, detectar isso (normalmente um page fault) e extender a memória da stack. :(

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

A memória que é utilizada pela pilha é normalmente chamada "memória automática".

Estou a ter um déja vu nesta discussão... ::(

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não o Njay tem razão o new é equivalente ao malloc do C aloca X espaço de memoria dinamicamente. O primeiro método aloca espaço estático, se for preciso mais memoria do que a alocada rebente xD

Pessoal, calma aí. É muito diferente. 'Reservar' aqui tem dois significados diferentes. Declarando uma variável de dados, quando se compila tem que se saber exactamente quanto espaço se precisa quanso se escreve o programa, caso contrario o código nem sequer é C++ válido.

Declarando um ponteiro, só em runtime é que é 'reservado' o tal espaço. No primeiro caso apanhamos as falhas de memória quando compilamos, no segundo quando a aplicação corre.

No exemplo deste tópico de facto é rigorosamente igual uma vez que já se sabe quanto espaço se vai usar aquando da compilação. Mas considerem o caso de um array de objectos.

int tamanho = 50; #esta variável pode levar um inteiro vindo de qq lado
Objecto *obj = new Objecto[tamanho] # no prob

Objecto obj [tamanho]; # isto dá m... nem sequer compila

Como podem ver não é só uma questão de preferencia.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mas ninguém estava a falar em alocar arrays :(

A questão era entre um (único) objecto alojado no stack e um (único) objecto alojado no heap. Obviamente que, se a sintaxe da linguagem não o permite, não se podem alocar arrays no stack utilizando uma variável para determinar o tamanho. Em C, no standard C99, passou a ser possível utilizar esta sintaxe. Em C++ ainda não é possível, pode ser que um dia passe a ser.

Já agora, "alocar" espaço no stack não se trata bem de alocar, trata-se unicamente de mover o stack pointer de forma a utilizar o espaço que já foi reservado para o stack. Exceptuando obviamente os casos em que é possível fazer crescer o stack.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Só que não é uma questão de sintaxe, na verdade a sintaxe até é válida. É mesmo uma questão de compilação, não podes mandar mover o stack pointer de forma que aponte para um sitio mas não lhe dizer que sítio é esse.

Não faço ideia como funciona esse tipo de declaração em C. Isso compila em qualquer situação? Não tem nenhuma restrição?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Já tivemos esta discussão há uns tempos. :(

Pois já. Daí o meu déjà vu anterior :cheesygrin:

Não faço ideia como funciona esse tipo de declaração em C. Isso compila em qualquer situação? Não tem nenhuma restrição?

Funciona quase exactamente como qualquer outra declaração de uma variável local. Mas em vez de adicionares um valor fixo ao stack pointer (add ESP, 10), adicionas o valor de uma variável (add ESP, [ESP - 8]).

Aquela sintaxe de assembly está um bocado enferrujada... mas acho que dá para passar a ideia :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora