Problema con il distruttore

di il
12 risposte

Problema con il distruttore

Buongiorno a tutti,
sono alle prese con un problema nella definizione del distruttore di una classe. Non riesco a capire che istruzioni devo dare al distruttore affinchè mi liberi la memoria occupata dall'oggetto senza darmi errore.
questo è quello che mi viene detto dal compilatore:
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001fd48b0 ***
grazie mille a chiunque proverà ad aiutarmi
#include <iostream>
#include <cmath>
#include<iomanip>//setw(int):regola cifre decimali  fixed
#include <cstring> 
#include <cstdlib> 
#include <fstream> 
#include <sstream> 
using namespace std;

class matrice
 {
  int a;//indica dimensione della matrice
  double **b;
  public:
  void diagonalizza(matrice m, matrice b, matrice vett)
   {
    for(int i=0;i<m.a;i++)
     {
      for(int j=0;j<m.a;j++)
       {
        matrice u(m, 1);
        matrice ut(m, 1);
        if(i!=j)
         {
          if(fabs(m[i][j])>1e-10)
           {
            double b=(m[i][i]-m[j][j])/(2*m[i][j]);
            double x1=b+sqrt(1+b*b);
            double x2=b-sqrt(1+b*b);
            double coseno;
            double seno;
            if(fabs(x1) <= fabs(x2))
             {
              coseno=1/sqrt(1+x1*x1);
              seno=x1/sqrt(1+x1*x1);
              }
            else
             {
              coseno=1/sqrt(1+x2*x2);
              seno=x2/sqrt(1+x2*x2);
              };
                    
            if(acos(coseno)> 1e-8)
             {
              ut[i][i]=coseno;
              ut[j][j]=coseno;
              ut[i][j]=-seno;
              ut[j][i]=seno;
              u[i][i]=coseno;
              u[j][j]=coseno;
              u[i][j]=seno;
              u[j][i]=-seno;
              m=(ut*m*u);
              vett*=u;
              u.matrice::~matrice();
              ut.matrice::~matrice();//errore
              
              }
            }
          }
        }
      }
    
    if(m==b)
     {
      for(int i=0;i<m.a;i++)
       {
        for(int j=0;j<m.a;j++)
         {
          if(fabs(m[i][j])<9.9999e-6)m[i][j]=0;
          }
        }
    
     for(int i=0;i<m.a;i++)
      {
       for(int j=0;j<m.a;j++)
        {
         if(fabs(vett[i][j])<9.9999e-6)vett[i][j]=0;
         }
       }
     cout<<"questa è la matrice diagonalizzata"<<endl<<m<<"e questa è la matrice degli autovettori"<<endl<<vett;
      }
    else
     {
      diagonalizza(m,m,vett);
      }
    }
  matrice(const matrice& c)
   {
    a=c.a;
    double** risultato=new double* [a];
    for(int i=0;i<a;i++)
     {
      risultato[i]=new double[a];
      for(int j=0;j<a;j++)
       {
        risultato[i][j]=c.b[i][j];
        }
      } 
    b=risultato;
    };
  ~matrice(){delete [] b;}//errore
  bool operator==(matrice g)
   {
    bool d=true;
    for(int i=0;i<a;i++)
     {
      for(int j=0;j<a;j++)
       {
        if(b[i][j]!=g.b[i][j]){d=false;}
        }
      }
    return d;
    }

  matrice()
   {
    cout<< "quale è la dimensione della matrice? ";
    cin >> a;
    double** d=new double* [a];
    for(int i=0;i<a;i++)
     {
      d[i]=new double[a];
      for(int j=0;j<a;j++)
       {
        cout <<"inserisci il valore in (" <<i+1 <<',' << j+1 << ") ";
        cin>>d[i][j];
        }
      }
    b=d;
    }

  matrice(matrice g, int h)
   {
    a=g.a;
    double** risultato=new double* [a];
    for(int i=0;i<a;i++)
     {
      risultato[i]=new double[a];
      for(int j=0;j<a;j++)
       {
        if(i!=j)
         {
          risultato[i][j]=0;
          }
        else
         {
          risultato[i][j]=h;
          }
        }
      } 
    b=risultato;
    }

  double* operator[](int e){return b[e];}

  matrice operator*(matrice d)
   {
    matrice res(d,0);
    res.a=a;
    double** risultato=new double* [a];
    for(int i=0;i<a;i++)
     {
      risultato[i]=new double[a];
      for(int j=0;j<a;j++)
       {
        risultato[i][j]=0;
        }
      } 
  
    for(int i=0;i<a;i++)
    { 
     for(int j=0;j<a;j++)
      {
       for(int k=0;k<a;k++)
        {
         risultato[i][k]+=(b[i][j]*d.b[j][k]);
         }
       }
     }
    res.b=risultato;
    return res;
    }
  friend void operator *=(matrice&, matrice);
  friend ostream &operator<<(ostream&, matrice);
  };

void operator *=(matrice &a, matrice b)
 {
  a=a*b;
  }

ostream &operator<<(ostream& stream, matrice a)
 {
  for(int i=0;i<a.a;i++)
   {
    for(int j=0;j<a.a;j++)
     {
      stream<<a.b[i][j]<<' ';
      }
     stream<<endl;
    }
  return stream;
  };

int main()
{
 matrice m;
 matrice vett(m,'a');
 m.diagonalizza(m,m,vett);
 }

12 Risposte

  • Re: Problema con il distruttore

    Ma per forza!!!!!

    Se istanzi la classe sullo stack, cioe' NON con new, il distruttore viene chiamato AUTOMATICAMENTE quando esci dallo SCOPE della sua dichiarazione!!!!!

    Nel secondo caso, NON CHIAMI esplicitamente il distruttore, perche' viene chiamato AUTOMATICAMENTE dalla delete.

    Devi STUDIARE MEGLIO come funziona l'allocazione/deallocazione delle classi (e relativa chiamata del costruttore/distruttore)

    !!!!!

    LEGGE DIVINA: NON SI CHIAMA MAI IL DISTRUTTORE ESPLICITAMENTE, a meno che tu non sia un DIO in C++
  • Re: Problema con il distruttore

    Premessa: non ho letto tutto, quindi potrebbe essere che quel che osservo non sia rilevante.

    Quando allochi, allochi con new un array di puntatori a double, poi allochi per ognuno di quei puntatori uno spazio adatto a contenere un vettore di double. E va be'.

    CREDO CHE il problema possa essere nel fatto che, quando deallochi, deallochi direttamente l'array dei puntatori senza prima deallocare ciascuno degli spazi adatti a contenere gli array di double.

    Ripeto, a scanso equivoci, che non ho analizzato tutto con attenzione e che non ho verificato niente, per cui sto un po' andando a tentoni. Verifica tu e vedi se quel che dico ha o non ha senso.

    Ps: ulteriori informazioni sul distruttore le puoi trovare qui -> http://tinyurl.com/ybp4r88
  • Re: Problema con il distruttore

    @AlfoBaldo, evita di andare aTENTONI in base a strane CREDENZE: NON E' magia o un rito satanico (vabbe' a volte lo potrebbe pure sembrare ).

    O ne sei SICURO, oppure lascia perdere. In questo caso: LASCIA PERDERE
  • Re: Problema con il distruttore

    Va bene, ma Il difetto che m'è sembrato di scorgere c'è o non c'è?
  • Re: Problema con il distruttore

    SCORGERE?

    Non deallocare qualcosa NON DA problemi di memoria corrotta!
    Semplicemente lasci in giro memoria allocata e non utilizzata.
    L'unica conseguenza e' che dopo un po' il programma non avrebbe piu' memoria disponibile da allocare.
    Quindi il problema si presenterebbe i fase di allocazione, NON in fase di deallocazione, e l'errore NON SAREBBE memoria corrotta, MA memoria insufficiente.
  • Re: Problema con il distruttore

    Bene, mi stai dicendo che quel che ho osservato non riguarda l'errore segnalato (in effetti non mi è mai capitato che mi venissero date segnalazioni di errore che riguardassero memory leaks, quei disgraziati passano inosservati finché non generano qualche malfunzionamento in momenti inattesi). Rileggendo le tue risposte precedenti ho anche preso atto di cose sensatissime che non avevo notato. La perdita di memoria che m'è sembrato di rilevare, però, c'è o non c'è? Perché quel che dicevo è che veniva rilasciato l'array dei puntatori senza prima rilasciare lo spazio di memoria puntato dai singoli puntatori, non altro. Dunque, se la matrice contiene, mettiamo, 5 righe e 7 colonne, verrà rilasciato il vettore che contiene i 5 puntatori alle righe, ma non verranno rilasciati i 5 spazi di memoria puntati e i relativi 5*7 elementi (divenuti, peraltro, "irrintracciabili" non avendone più a disposizione i puntatori).
    double **b; // proprieta' della classe matrice
    
    /* = = = */
    
    // nella funzione creatrice della classe matrice...
    
    double** d=new double* [a]; // alloca l'array dei puntatori alle "righe"
        
    for(int i=0;i<a;i++) {
        d[i] = new double[a]; // alloca gli elementi delle singole "righe"
    }
        
    b = d;
    
    /* = = = */
    
    // nella funzione distruttrice della classe matrice...
    
    delete[] b; // dealloca l'array dei puntatori alle righe ma
                // non quelli degli elementi delle singole righe
    
    A me questo sembra un errore, anche se avviene senza segnalazioni da parte del compilatore.
  • Re: Problema con il distruttore

    Quindi se ho capito bene devo lasciare la chiamata del distruttore sottintesa. devo anche ridefinire il distruttore oppure in questo caso va bene anche quello default? lasciando la chiamata sottintesa mi devo preoccupare di finire la memoria oppure ci pensa il distruttore a liberarmi la memoria occupata?
    ultima domanda: dove mi consigliate di studiare questi argomenti?
  • Re: Problema con il distruttore

    davide123 ha scritto:


    Quindi se ho capito bene devo lasciare la chiamata del distruttore sottintesa. devo anche ridefinire il distruttore oppure in questo caso va bene anche quello default? lasciando la chiamata sottintesa mi devo preoccupare di finire la memoria oppure ci pensa il distruttore a liberarmi la memoria occupata?
    ultima domanda: dove mi consigliate di studiare questi argomenti?
    Se nell'implementazione della classe hai allocato degli oggetti con una new/malloc, prima o poi devi fare una delete/free . Tieni conto che questo è vero salvo quei casi, non rari, in cui le risorse allocate devono continuare a "vivere" anche dopo che la classe viene distrutta perchè devono essere usate anche altrove, anche perchè distruggere una risorsa che ha un puntatore anche da "qualche altra parte" nel programma ti porta ad avere un Dangling Pointers (puntatore pendente) ovvero un puntatore che punta a qualcosa che non esiste più. Pertanto, in linea generale, devi ridefinire il distruttore liberando tutte le risorse che hai allocato durante il ciclo di vita dell'oggetto istanziato, altrimenti ottieni dei memory leak. È importante chiaramente controllare sempre che le risorse che si stanno per deallocare non siano già state rilasciate per non avere un double free e problemi di memory corruption.

    N.B: Per evitare tutte queste problematiche in alcune circostanze è utile usare smart pointer come lo std::shared_ptr definito dallo standard c++11.
  • Re: Problema con il distruttore

    Dato che la mia classe è formata da un intero e un puntatore di puntatori come faccio a liberare la memoria occupata dall'intero?
  • Re: Problema con il distruttore

    @davide123, ma che acciderbolina di domande fai !
    Stai studiando il linguaggio di programmazione su Topolino?
    Attento che Paperoga NON E'un buon insegnante!

    RAGIONA!

    Hai mai giocato con i Lego o con qualunque altro tipo di costruzione (Meccano)?

    C'e' una regola BANALE che si puo' seguire: le cose di smontano nel modo contrario a come sono state create!

    Se il codice e' farina del tuo sacco, ti dovrebbe essere chiaro come fare!
  • Re: Problema con il distruttore

    davide123 ha scritto:


    ...come faccio a liberare la memoria occupata dall'intero?
    L'intero a nel tuo caso specifico viene liberato automaticamente quando viene chiamato il distruttore della classe matrice.
  • Re: Problema con il distruttore

    Ok grazie mille. mi stavo facendo problemi inesistenti
Devi accedere o registrarti per scrivere nel forum
12 risposte