Julien D
Julien D

Reputation: 9

Constructor segmentation fault

I realize that there have been questions similar to this one, and that the problem is likely related to dereferencing of a pointer, but I have tried suggestions from similar questions and can't seem to get rid of the segmentation fault. The error seems to occur in the constructor of ArbolGeneral.cpp. I am new to C++.

Here is the main function:

#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "diccionario.h"


int main(int argc, char * argv[]){
  if (argc!=2){
    cout<<"Los parametros son:"<<endl;
    cout<<"1.- El fichero con las palabras"<<endl;

    return 0;
  }

  ifstream f(argv[1]);
  info ii(' ', false);
  cout<<"Cargando diccionario...."<<endl;
  Diccionario D;
  cout<<"todavia aqui"<<endl;
  f>>D;
  cout<<"Leido el diccionario..."<<endl;
  cout<<D;

  int longitud;

  cout<<"Dime la longitud de las palabras que quieres ver";
  cin>>longitud;
  vector<string> v=D.PalabrasLongitud(longitud);

  cout<<"Palabras de Longitud "<<longitud<<endl;
  for (unsigned int i=0;i<v.size();i++)
    cout<<v[i]<<endl;

 string p;
 cout<<"Dime una palabra: ";
 cin>>p;
 if (D.Esta(p)){
    cout<<"Sí esa palabra existe";
 }
 else
    cout<<"Esa palabra no existe";

}

Followed by the relevant code in the ArbolGeneral.h (Generic tree) :

template <class T>
class ArbolGeneral{
/**
  * @page repConjunto Rep del TDA Arbol General
  *
  * @section invConjunto Invariante de la representación
  *
  * Añadir el invariante de la representación
  *
  * @section faConjunto Función de abstracción
  *
  * Añadir la función de abstracción
  */

  private:
    /**
      *@brief nodo
      *
      * En cada  estructura \e nodo se almacena una etiqueta del árbol, que se 
      * implementa como un conjunto de nodos enlazados según la relación 
      * padre-hijo más a la izquierda-hermano derecha.
      */
    struct nodo {
      /**
        *@brief Elemento almacenado
        *
        * En este campo se almacena la etiqueta que corresponde a este nodo.
        */
      T etiqueta;

      /**
        * @brief Puntero al hijo más a la izquierda
        *
        * En este campo se almacena un puntero al nodo raíz del subárbol más a 
        * la izquierda, o el valor 0 si no tiene.
        */
      nodo *izqda;

      /**
        * @brief Puntero al hermano derecho
        *
        * En este campo se almacena un puntero al nodo raíz del subárbol 
        * hermano derecho, o el valor 0 si no tiene.
        */
      nodo *drcha;

      /**
        * @brief Puntero al padre
        *
        * En este campo se almacena un puntero al nodo padre, o el valor 0 si 
        * es la raíz.
        */
       nodo *padre;

       nodo() : padre(0),drcha(0),izqda(0) {}
    };

    /**
      * @brief Puntero a la raíz.
      *
      * Este miembro es un puntero al primer nodo, que corresponde a la raíz 
      * del árbol. Vale 0 si el árbol es vacío.
      */
    struct nodo *laraiz;

    /**
      * @brief Destruye el subárbol
      * @param n Nodo a destruir, junto con sus descendientes
      *
      * Libera los recursos que ocupan \e n y sus descendientes.
      */
    void destruir(nodo * n);

    public:
/**
  * @brief Tipo Nodo
  * 
  * Este tipo nos permite manejar cada uno de los nodos del árbol. Los 
  * valores que tomará serán tantos como nodos en el árbol (para poder 
  * referirse a cada uno de ellos) y además un valor destacado
  * \e nulo (0), que indica que no se refiere a ninguno de ellos.
  *
  * Una variable \e n de este tipo se declara
  *
  * <tt>ArbolGeneral::Nodo n;</tt>
  *
  * Las operaciones válidas sobre el tipo nodo son:
  *
  * - Operador de Asignación (=).
  * - Operador de comprobación de igualdad (==).
  * - Operador de comprobación de desigualdad (!=).
  */
typedef struct nodo * Nodo;


/**
  * @brief Constructor por defecto
  *
  * Reserva los recursos e inicializa el árbol a vacío {}. La operación se
  * realiza en tiempo O(1).
  */
ArbolGeneral();

/**
  * @brief Constructor de raíz
  * @param e Etiqueta de la raíz
  *
  * Reserva los recursos e inicializa el árbol con un único nodo raíz que 
  * tiene la etiqueta \e e, es decir, el árbol {e, {}, {}}. La operación 
  * se realiza en tiempo O(1).
  */
ArbolGeneral(const T& e);

Here is the constructor in ArbolGeneral.cpp :

template <class T>
inline ArbolGeneral<T>::ArbolGeneral(){
    laraiz = 0;
    }
/*--------------------------------*/
template <class T>
ArbolGeneral<T>::ArbolGeneral(const T& e) : laraiz(new nodo)
{
    laraiz -> etiqueta = e;  //  <---- Error Here
}

/*--------------------------------*/
template <class T>
ArbolGeneral<T>::ArbolGeneral (const ArbolGeneral<T>& v){
    copiar(laraiz, v.laraiz);
    if (laraiz != 0)
    {
        laraiz -> padre = 0;
    }
}

/*--------------------------------*/
template <class T>
inline ArbolGeneral<T>::~ArbolGeneral(){
    destruir(laraiz);
}

And finally the initial call I make which causes the segFault :

Diccionario::Diccionario(){
    info inf('0', false);
    datos = ArbolGeneral<info>(inf);
}

The output I get is as follows:

Cargando diccionario....
Segmentation fault: 11

I know it's a lot to go through but I wanted to include everything that could be relevant as I have no idea what is causing the error.

EDIT: Adding in methods for assignment operator,copiar and destruir.

template <class T>
ArbolGeneral<T>& ArbolGeneral<T>::operator = (const ArbolGeneral<T> &v){
    if (this!=&v)
    {
        destruir(laraiz);
        copiar(laraiz,v.laraiz);
        if (laraiz!= 0)
        {
            laraiz -> padre = 0;
        }
    }
    return *this;
}

template <class T>
void ArbolGeneral<T>::destruir(nodo *n){
    //destruccion recursiva
    if (n!=0)
    {
        destruir(n -> izqda);
        destruir(n -> drcha);
        delete n;
    }
}

/*--------------------------------*/
template <class T>
void ArbolGeneral<T>::copiar(nodo *& dest, nodo * orig){
    if (orig == 0) //caso nulo
    {
        dest = 0;
    } else{ //caso general
        dest->etiqueta = orig->etiqueta;
        copiar(dest -> izqda,dest -> drcha);
        copiar(dest -> drcha,dest->drcha);
        if (dest -> izqda != 0)
        {
            dest -> izqda -> padre = dest;
        }
        if (dest -> drcha != 0)
        {
            dest -> drcha -> padre = dest -> padre;
        }
    }
}

Upvotes: 0

Views: 361

Answers (1)

Vaughn Cato
Vaughn Cato

Reputation: 64308

You are doing an assignment of an ArbolGeneral:

datos = ArbolGeneral<info>(inf);

You also have manual memory management in ArbolGeneral:

template <class T>
inline ArbolGeneral<T>::~ArbolGeneral(){
    destruir(laraiz);
}

But you don't define an assignment operator to define how the memory should be managed during assignment. This leads to destruir() being called twice for the same object.

You need to either define the assignment operator, disable the assignment operator, or remove the manual memory management. Same applies to the copy constructor.

See What is The Rule of Three?

Upvotes: 3

Related Questions