构造函数分段错误

时间:2016-01-24 21:43:10

标签: c++ segmentation-fault

我意识到存在与此类似的问题,并且该问题可能与指针的解除引用有关,但我尝试过类似问题的建议,似乎无法摆脱分段错误。该错误似乎发生在ArbolGeneral.cpp的构造函数中。我是C ++的新手。

这是主要功能:

#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";

}

随后是ArbolGeneral.h(通用树)中的相关代码:

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);

这是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);
}

最后我做的初始调用导致了segFault:

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

我得到的输出如下:

Cargando diccionario....
Segmentation fault: 11

我知道要经历很多事情,但我想要包含一些可能相关的内容,因为我不知道导致错误的是什么。

编辑:添加赋值运算符,copiar和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;
        }
    }
}

1 个答案:

答案 0 :(得分:3)

您正在分配ArbolGeneral:

datos = ArbolGeneral<info>(inf);

您还可以在ArbolGeneral中进行手动内存管理:

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

但是,您没有定义赋值运算符来定义在赋值期间应如何管理内存。这导致destruir()被同一个对象调用两次。

您需要定义赋值运算符,禁用赋值运算符或删除手动内存管理。同样适用于复制构造函数。

请参阅What is The Rule of Three?