Ir para conteúdo
Fórum Script Brasil
  • 0

porque o malloc chama o destructor?


kuroi

Pergunta

isso no dev c++.

porque quando aloco a memoria para o objeto, ele chama o destructor logo em seguida ao constuctor??

exemplo, se eu tenho essa classe:

class minha_classe
{
   public : minha_classe()
    {
        printf("1");
    }
    ~minha_classe()
    {
       printf("\ndestrutor\n");
    }
};[/code] agora, imagine q eu faca isso:
[code]int main()
{
    minha_classe x = minha_classe();
    
    printf("2");

    return 0;
}
o meu retorno esta sendo o seguinte:
12 destrutor
isso esta certinho, ele so chama o destrutor na hora q o programa fecha. agora imagine q eu faca isso:
int main(int argc, char* args[])
{
    minha_classe* x;
    
    x = (minha_classe*)malloc(sizeof(minha_classe));
    *x = minha_classe();

    printf("2");
    
    delete x;
    
    return 0;
}[/code]

o retorno é esse:

1

destrutor

2

destrutor

ou seja, isso significa q o destrutor esta sendo chamado duas vezes. a primera, logo depois do construtor, e a segunda, no delete.

qual é o sentido de ele ser chamado junto com o construtor?? era pra ser normal??

com o new, não tenho esse problema. entretanto, não queria usar o new por q com ele eu estava tendo outro problema, q foi discutido nesse tópico aqui: http://scriptbrasil.com.br/forum/index.php?showtopic=142460

Link para o comentário
Compartilhar em outros sites

8 respostass a esta questão

Posts Recomendados

  • 0

Não é o malloc que chama o destruidor, observe:

#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
using std::cin;

class Teste {
  friend ostream &operator<<(ostream &, const Teste &);
public:
  Teste(void) { info = 1337;cout<<"Construtor!"<<endl; }
  ~Teste(void) { cout<<"Destruidor!"<<endl; }
private:
  int info;
};

ostream &operator<<(ostream &outp, const Teste &tst)
{
  outp<<(tst.info);
  return outp;
}

int main(void)
{
  cout<<(Teste())<<endl;
  return 0;
}
Saída:
douplus@domain:~/ajudas$ ./teste
Construtor!
1337
Destruidor!
douplus@domain:~/ajudas$
Isso mostra que chamar um construtor fora de inicialização de variável faz com que ele retorne por valor um objeto da classe e automáticamente o destrói como se tivesse sido criado um escopo para aquele instante. Isso deve ser uma medida de precaução e gerenciamento de memória, uma vez que o esse objeto criado não tem mais como ser tratado no programa. A função malloc() não chama construtor, por isso que se deve usar new em C++. Por isso, e pelo que foi demonstrado no programa de teste, não é a malloc que está chamando o destruidor: o objeto simplesmente se destrói. O próximo passo é entender de onde vem a segunda chamada ao destruidor. A segunda chamada ao destruidor ocorre após o "2" ser mostrado na tela, logo após a chamada de printf() o delete é chamado. Se a memória apontada pelo ponteiro foi alocada sem a invocação do construtor, faz sentido um construtor ser executado com delete sem antes ter sido chamado um construtor? Observe:
#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
using std::cin;

class Teste {
  friend ostream &operator<<(ostream &, const Teste &);
public:
  Teste(void) { info = 1337;cout<<"Construtor!"<<endl; }
  ~Teste(void) { cout<<"Destruidor!"<<endl; }
private:
  int info;
};

ostream &operator<<(ostream &outp, const Teste &tst)
{
  outp<<(tst.info);
  return outp;
}

int main(void)
{
  Teste *tst;
  delete tst;
  cin.get();
  return 0;
}
Coloquei um cin.get() para garantir que a chamada do destruidor não ocorre com o término do escopo de main() e sim com delete. Veja a saída:
douplus@domain:~/ajudas$ ./teste
Destruidor!
Segmentation fault
douplus@domain:~/ajudas$
O programa sequer esperou a cin.get() e ocorrou uma segmentation fault. Por garantia fiz o teste sem o delete e sem a cin.get():
int main(void)
{
  Teste *tst;
  //delete tst;
  //cin.get();
  return 0;
}
Saída:
douplus@domain:~/ajudas$ ./teste
douplus@domain:~/ajudas$

Sem segmentation fault e sem saída na tela.

CONCLUSÕES:

: No seu código, além da invocação explícita do destruidor com o operador delete, houve outra implícita ocasionada pela chamada após o construtor ter retornado o objeto

: Com new o objeto não seria destruído e o construtor provavelmente só seria chamado uma vez neste código.

: O teste que fiz resultou em segmentation fault porque não havia memória alocada onde delete operou. No seu código havia memória alocada por malloc()

Link para o comentário
Compartilhar em outros sites

  • 0

valeu douplus, entendi o q acontece.

mas o problema do meu otro tópico ainda permanece. agora eu descobri q não posso usar o malloc, senao ele chama o destrutor (q vai desalocar espacos q eu aloquei dentro da classe, o q vai impedir o objeto de funcionar corretamente).

e eu não consigo usar o new porque ele espera q eu passe parametros q eu não tenho como passar:

ooo = new lista_ligada<opcao>;

não posso usar esse codigo porque o constructor da classe opcao espera parametros. se existir um modo de passar os parametros nessa linha resolveria, mas não encontrei como fazer isso.

e mesmo se eu fizesse um constructor sem parametros, logo depois eu teria q chamar o constructor q possui os parametros. alem de ser perda de tempo chamar dois constructors, isso não resolveria nd, porque quando eu chamasse o constructor a segunda vez, ele deve chamar tb o destructor e o meu problema continuaria.

bom, levando isso em conta, vejo duas opcoes pra mim:

1 - usar um construtor sem parametros e, na hora de inserir o item na lista, eu alteraria as propriedades dele na mao no lugar do constructor antigo, o q é uma coisa q não quero fazer de jeito nenhum.

2 - descartaria essa struct da lista ligada q criei q aceita qualquer tipo e teria q fazer uma classe lista pra cada objeto q eu for usar com a lista, e fazer um construct nessa classe lista identico ao construct do objeto relacionado a ela. assim, eu passaria os parametros para a lista ligada q passaria para o objeto. o q tb é uma coisa q não me anima nd fazer.

alguém tem uma ideia melhor??

valeu.

EDITADO:

pensei numa terceria opcao aqui:

3 - em vez de armazenar o objeto dentro da lista ligada, eu armazenaria o pontero dele.

acho q isso resolveria tudo sem estragar a programacao.

mas se tiverem otras ideias ou algum comentario, postem ai.

valeu.

Editado por kuroi
Link para o comentário
Compartilhar em outros sites

  • 0
mas se tiverem otras ideias ou algum comentario, postem ai.

valeu.

Que tal essa:

template <class T>
struct lista_ligada
{
  lista_ligada(T info) { item = info; }   // Eu já poria l = NULL aqui.
  T item;
  lista_ligada<T>* l;
};
public : opcao* NovaOpcao(area* ax, SDL_Surface* h, int offx, int offy)
{            
    opcao* r;          
              
    if (ooo == NULL) //Primeira área a ser adicionada.
    {
      ooo = new lista_ligada<opcao>(opcao(ax, h, offx, offy));
        ooo->item = opcao(ax, h, offx, offy);
        ooo->l = NULL;
        qtde = 1;
        
        //ColocaFoco(&(ooo->item));
        foco = &(ooo->item);
        
        r = &(ooo->item);
    }
    else
    {
        lista_ligada<opcao>* ppp = ooo;
        while (ppp->l != NULL)
        {
            ppp = ppp->l;
        }
        ppp->l = new lista_ligada<opcao>(opcao(ax, h, offx, offy));   //<-- não FUNCIONA
        ppp->l->item = opcao(ax, h, offx, offy);
        ppp->l->l = NULL;
        qtde++;
        
        r = &(ppp->l->item);
    }
    
    return r;
}

?

Até mais!

Editado por == Douplus ==
Link para o comentário
Compartilhar em outros sites

  • 0

valeu douplus. mas então, esse "<-- não FUNCIONA" q ficou no codigo é so porque você esqueceu de apagar o comentario q eu deixei ou é porque não funciona mesmo??

porque realmente não ta funcionando hehe

então, primera coisa q por algum motivo, ele não aceita o new a não ser q eu crie um construtor sem parametros pra classe opcao. senao ele da essa mensagem:

no matching function for call to `opcao::opcao()'

e aponta pra linha:

lista_ligada(T info) {

e outra coisa é q, se eu crio o constuctor sem parametros, o new (com parametros) funciona certinho. entretanto, o destructor é chamado logo depois do constructor, como sempre.

mas legal esse codigo q você passou. aquilo é como criar um construtor para a struct, não sabia q dava pra fazer isso.

sera então q o jeito vai ser eu seguir aquela opcao 3 de q eu falei??

valeu pela ajuda ate aqui.

Editado por kuroi
Link para o comentário
Compartilhar em outros sites

  • 0
não funciona:
o destructor é chamado logo depois do constructor, como sempre.

Isso é normal! O objeto destruído é o que foi usado pra cópia enão o ooo->item

Fiz umas alterações e um programa de teste pra ver se esclarece:

#include <iostream>
using std::cout;
using std::endl;

// Para teste:
typedef int area;
typedef int SDL_Surface;

template <class T>
struct lista_ligada
{
  lista_ligada(T info) { item = info; l = NULL; }
  T item;
  lista_ligada<T>* l;
};

class opcao
{
    public : area* Area; //Área da tela onde está a opção.
    
    public : opcao* Baixo; //Para qual opção irá ao ser pressionado para baixo.
    public : opcao* Cima; //Para qual opção irá ao ser pressionado para cima.
    public : opcao* Esquerda; //Para qual opção irá ao ser pressionado para a esquerda.
    public : opcao* Direita; //Para qual opção irá ao ser pressionado para a direita.
    
    //Para alinhar o highlight à área.
    public : int offset_x;
    public : int offset_y;
    
    public : SDL_Surface* highlight_img; //Imagem que circundará a opção em highlight;
    
public : opcao(void) { cout<<"opcao(void)"<<endl; }
    public : opcao(area* ax, SDL_Surface* h, int offx, int offy)
    {
        Area = ax;        
        highlight_img = h;
        
        offset_x = offx;
        offset_y = offy;
        
        Baixo = NULL;
        Cima = NULL;
        Esquerda = NULL;
        Direita = NULL;
cout<<"opcao(area *, SDL_Surface *, int, int)"<<endl;
    }
  ~opcao() { cout<<"~opcao()"<<endl; }
};

class Teste {
public:
  Teste(void) : ooo(NULL) { }
opcao* NovaOpcao(area* ax, SDL_Surface* h, int offx, int offy)
{            
    opcao* r;          
              
    if (ooo == NULL) //Primeira área a ser adicionada.
    {
      ooo = new lista_ligada<opcao>(opcao(ax, h, offx, offy));
      // Essa linhas saem:
      //  ooo->item = opcao(ax, h, offx, offy);
      //  ooo->l = NULL;
        qtde = 1;
        
        //ColocaFoco(&(ooo->item));
        foco = &(ooo->item);
        
        r = &(ooo->item);
    }
    else
    {
        lista_ligada<opcao>* ppp = ooo;
        while (ppp->l != NULL)
        {
            ppp = ppp->l;
        }
        ppp->l = new lista_ligada<opcao>(opcao(ax, h, offx, offy));   //<-- não FUNCIONA
        // Essas tmabém:
    //ppp->l->item = opcao(ax, h, offx, offy);
        //ppp->l->l = NULL;
        qtde++;
        
        r = &(ppp->l->item);
    }
    
    return r;
}
protected:
  lista_ligada<opcao> *ooo;
private:
  int qtde;
  opcao *foco;
  };

int main(void)
{
  Teste teste;
  area ar = 1;
  SDL_Surface surf = 2;

  opcao *optr = teste.NovaOpcao(&surf, &ar, 2, 3);

  cout<<"Area = "<<(*(optr->Area))
      <<"\nHighlight IMG: "<<(*(optr->highlight_img))
      <<"\nx = "<<optr->offset_x<<"\ny = "<<optr->offset_y<<endl;
  return 0;
}
Saída:
$ ./durub3
opcao(area *, SDL_Surface *, int, int)
opcao(void)
~opcao()
Area = 2
Highlight IMG: 1
x = 2
y = 3
$
Repare que as variáveis de opcao da lista alocada continuam intáctas e não dão erro de memória porque não foram destruídas. Usei o GDB para analizar as chamadas de construtores e destruidores:
(gdb) r                                             
Starting program: /home/douplus/ajudas/durub3       

Breakpoint 1, main () at durub3.cpp:97
97        Teste teste;                
(gdb) s                               
Teste (this=0xbfa05b98) at durub3.cpp:52
52        Teste(void) : ooo(NULL) { }   
(gdb)                                   
main () at durub3.cpp:98                
98        area ar = 1;                  
(gdb)                                   
99        SDL_Surface surf = 2;         
(gdb)                                   
101       opcao *optr = teste.NovaOpcao(&surf, &ar, 2, 3);
(gdb)                                                     
Teste::NovaOpcao (this=0xbfa05b98, ax=0xbfa05b90, h=0xbfa05b94, offx=2, offy=3) at durub3.cpp:57
57          if (ooo == NULL) //Primeira área a ser adicionada.                                  
(gdb)                                                                                           
59            ooo = new lista_ligada<opcao>(opcao(ax, h, offx, offy));                          
(gdb)                                                                                           
opcao (this=0xbfa05b08, ax=0xbfa05b90, h=0xbfa05b94, offx=2, offy=3) at durub3.cpp:35           
35              Area = ax;                                                                      
(gdb)                                                                                           
36              highlight_img = h;                                                              
(gdb)                                                                                           
38              offset_x = offx;                                                                
(gdb)                                                                                           
39              offset_y = offy;                                                                
(gdb)                                                                                           
41              Baixo = NULL;                                                                   
(gdb)                                                                                           
42              Cima = NULL;                                                                    
(gdb)                                                                                           
43              Esquerda = NULL;                                                                
(gdb)                                                                                           
44              Direita = NULL;                                                                 
(gdb)                                                                                           
45      cout<<"opcao(area *, SDL_Surface *, int, int)"<<endl;                                   
(gdb)                                                                                           
opcao(area *, SDL_Surface *, int, int)                                                          
46          }                                                                                   
(gdb)                                                                                           
lista_ligada (this=0x804a008, info=                                                             
      {Area = 0xbfa05b08, Baixo = 0xb7fa77f0, Cima = 0xb7f20fc7, Esquerda = 0x3df6174, Direita = 0xb7fe9ff4, offset_x = 134513120, offset_y = -1208048024, highlight_img = 0xbfa05b08}) at durub3.cpp:12
12        lista_ligada(T info) { item = info; l = NULL; }                                                                                                                                               
(gdb)                                                                                                                                                                                                   
opcao (this=0x804a008) at durub3.cpp:32                                                                                                                                                                 
32      public : opcao(void) { cout<<"opcao(void)"<<endl; }                                                                                                                                             
(gdb)                                                                                                                                                                                                   
opcao(void)                                                                                                                                                                                             
~opcao (this=0xbfa05b08) at durub3.cpp:47                                                                                                                                                               
47        ~opcao() { cout<<"~opcao()"<<endl; }                                                                                                                                                          
(gdb)                                                                                                                                                                                                   
~opcao()                                                                                                                                                                                                
Teste::NovaOpcao (this=0xbfa05b98, ax=0xbfa05b90, h=0xbfa05b94, offx=2, offy=3) at durub3.cpp:63                                                                                                        
63              qtde = 1;                                                                                                                                                                               
(gdb)
66              foco = &(ooo->item);
(gdb)
68              r = &(ooo->item);
(gdb)
86          return r;
(gdb)
87      }
(gdb)
main () at durub3.cpp:105
105           <<"\nx = "<<optr->offset_x<<"\ny = "<<optr->offset_y<<endl;
(gdb)
Area = 2
Highlight IMG: 1
x = 2
y = 3
106       return 0;
(gdb)
107     }
(gdb)
0xb7d426a5 in __libc_start_main () from /lib/libc.so.6
(gdb)
Single stepping until exit from function __libc_start_main,
which has no line number information.

Program exited normally.
(gdb)
O que aconteceu foi: 1) linha 101 cria uma opção; 2) linha 59 cria lista de opcao;
59            ooo = new lista_ligada<opcao>(opcao(ax, h, offx, offy));

3) construtor opcao(area *, SDL_Surface *, int, int) chamado;

4) construtor de lista_ligada chamado;

5) construtor de lista_ligada por sua vez chama construtor opcao(void);

6) (opcao(ax, h, offx, offy)) da linha 59 foi copiado para ooo->item[]b/;

7) destruidor ~opcao() chamado para destruir (opcao(ax, h, offx, offy)) na linha 59;

8) Não foi chamado o destruidor de ooo->item;

CONCLUSÃO:

ooo->item não foi destruído! Pode usá-lo.

Editado por == Douplus ==
Link para o comentário
Compartilhar em outros sites

  • 0

valeu douplus. mas então... eu sei q ooo->item não é destruido e q eu posso usa-lo. esse não era meu problema desde o comeco, se fosse isso o meu codigo do malloc taria funcionando e eu nem teria aberto o tópico. eu nem ia ter percebido q o destructor tava sendo chamado.

meu problema é q:

ele chama o destrutor (q vai desalocar espacos q eu aloquei dentro da classe, o q vai impedir o objeto de funcionar corretamente).

o meu problema é aquela propriedade highlight_img do tipo SDL_Surface*, alem de outras tres propriedades desse tipo q eu já inclui na classe.

talvez isso não tenha ficado claro, porque você deve ter pensado q eu ainda tava usando a classe opcao com a estrutura q ta no outro tópico (q não tem nd no destructor). mas na verdade, eu to fazendo um novo projeto usando esse mesma classe, mas foram feitas alteracoes nela. atualmente esta assim:

class opcao
{
    public : area* Area; //Área da tela onde está a opção.
    
    public : opcao* Baixo; //Para qual opção irá ao ser pressionado para baixo.
    public : opcao* Cima; //Para qual opção irá ao ser pressionado para cima.
    public : opcao* Esquerda; //Para qual opção irá ao ser pressionado para a esquerda.
    public : opcao* Direita; //Para qual opção irá ao ser pressionado para a direita.    
    
    public : SDL_Surface* img; //Imagem da opção.
    public : SDL_Surface* highlight_img; //Imagem de highlight.
    public : SDL_Surface* clique_img; //Imagem quando a opção for clicada.
    public : SDL_Surface* inativa_img; //Imagem quando estiver inativa.    
    
    public : E_Eventos ev_mousedown;
    public : E_Eventos ev_mouseup;
    
    public : bool Ativo;
    
    public : opcao(area* ax, SDL_Surface* im, SDL_Surface* h, SDL_Surface* c, SDL_Surface* in)
    {
        Area = ax;              
        
        Ativo = true;  
        
        img = im;
        highlight_img = h;
        clique_img = c;
        inativa_img = in;        
        
        ev_mousedown = EV_NENHUM;
        ev_mouseup = EV_NENHUM;
        
        Baixo = NULL;
        Cima = NULL;
        Esquerda = NULL;
        Direita = NULL;        
    }
    ~opcao()
    {
        if (img != NULL) SDL_FreeSurface(img);
        if (highlight_img != NULL) SDL_FreeSurface(highlight_img);
        if (clique_img != NULL) SDL_FreeSurface(clique_img);
        if (inativa_img != NULL) SDL_FreeSurface(inativa_img);
    };
};[/code]

o problema é q na hora q o destructor é chamado, ele desaloca o espaco dos SDL_Surfaces. os enderecos dos SDL_Surfaces q serao copiados para o espaco alocado do objeto opcao são os mesmos q serao passados para o constructor e os mesmos q serao desalocados no destructor. então eu vou perder meus SDL_Surfaces se o destructor for chamado.

eu poderia em vez de armazenar o pontero do SDL_Surface, q eu armazenasse o proprio SDL_Surface dentro da classe. e ai eu teria q desalocar os espacos no programa principal depois de passa-los ao objeto ou ainda destrui-los dentro do proprio constructor (porque os SDL_Surfaces são carregados com a funcao IMG_Load() do sdl, q aloca o espaco para a imagem e retorna o pontero. então querendo ou não, eu vou ter q chamar o SDL_FreeSurface() em algum momento).

mas se for pra fazer isso, prefiro seguir a ideia da minha opcao 3 no post mais acima.

alem do mais, pelo q eu entendi do processo, quando eu to chamando o new, ele ta instanciando o objeto num endereco de memoria temporario qualquer e chamando o constructor. depois ele copia todo o objeto já inicializado para o endereco alocado pelo new e destroi o objeto temporario.

ou seja, eu to perdendo tempo copiando o objeto todo, coisa q poderia ser evitada.

hum, não sei se isso vai ter otra solucao, mas de qualquer forma valeu pela ajuda ate ai, deu pra aprender umas coisas novas.

Editado por kuroi
Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,3k
    • Posts
      652,5k
×
×
  • Criar Novo...