-3

二重リンク リストを実装していますが、メンバー ポインターが指すオブジェクトの真正なメンバーにアクセスしようとすると、segfault が発生します。リンクされたリストは、値と次および前のポインターを持つノードで構成されています

文字列 (これは以前のプロジェクトの必要最小限の実装です):

class String{
    public:
    int len;
    char *str;

    String()
    :len(0), str(nullptr){}

    String(char const* S)
    :len(strlen(S)), str(new char[len +1]){
        assert(S != 0);
        strcpy(str, S);
    }

    ~String(){
        delete[]str;
    }
};

ノード (これが「ビッグ 3」を実装していないことはわかっています。むしろ、このクラスを最小限に抑えたいと思います):

#include <initializer_list>

    template<typename T>
    struct Node{
      T value;
      Node* next;
      Node* prev;

      Node() = default;
      Node(T t, Node* n, Node* p)
      :value(t), next(n), prev(p){}

      Node & operator=(const Node & N){
        value = N.value;
        next = N.next;
        prev = N.prev;
        return *this;
      }
    };

二重にリンクされたリスト:

template<typename T>
struct List
{
  List(std::initializer_list<T>);
  Node<T>* head;
  Node<T>* tail;
  List()
  :head(nullptr), tail(nullptr){}

  //copy constructor
  List(const List<T> & l){
    Node<T>* p = l.head;
    head = p;
    Node<T>* past;
    while(p){
      Node<T>* q = new Node<T>;
      *q = *p;
      if(head == p){
        head = q;
      }else{
        past->next = q;
        q->prev = past;
      }
      past = q;
      p = q->next;
    }
    tail = past;
  }


  //copy assignment
  List & operator=(const List & L){
    List temp = L;
    swap (*this, temp);
    return *this;
  }

  Node<T>* getHead()const{
    return head;
  }

  Node<T>* getTail()const{
    return tail;
  }

  void swap(List a, List b){
    Node<T>* temp1 = a.getHead();
    Node<T>* temp2 = a.getTail();

    a.head = b.getHead();
    a.tail = b.tail;
    b.head = temp1;
    b.tail = temp2;
  }

  void push_back(T t){
    Node<T>* p = new Node<T>(t, nullptr, tail);
    if(tail){
      tail->next = p; //Segfault occurs here
    }else{
      head = p;
    }
    tail = p;
  }

  int compare(const List<T> & b)const{
    Node<T>* temp1 = this->head;
    Node<T>* temp2 = b.head;
    while (temp1 != this->tail && temp2 != b.tail) {
      if (temp1->value < temp2->value)
        return -1;
      if (temp2->value < temp1->value)
        return 1;
    }
    if (temp1 == this->tail) {
      if (temp2 != this->tail)
        return -1; // [first1, last1) is a prefix of [first2, last2)
      else
        return 0;  // [first1, last1) and [first2, last2) are equivalent
    }
    else {
      return 1;    // [first2, last1) is a prefix  of [first1, last1)
    }
  }

  size_t size()const{
    size_t n = 0;
    Node<T> *p = head;
    while (p){
      ++n;
      p = p->next;
    }
    return n;
  }

  void clear(){
    Node<T> *p = head;
    while(p){
      Node<T>* q = p-> next;
      delete[] p;
      p = q;
    }
    head = tail = nullptr;
  }

  ~List<T>(){
    clear();
  }
};

template<typename T>
List<T>::List(std::initializer_list<T> list)
{
  for (T const& elem : list)
    push_back(elem);
}

主要:

int main()
{
    List<String> v1 =  {"a", "b", "c"}; //segfault occurs on second pass of initialization loop
    return 0;
}

どんな助けでも大歓迎です!

4

1 に答える 1

2

ノード (これが「ビッグ 3」を実装していないことはわかっています。むしろ、このクラスを最小限に抑えたいと思います):

コピー/移動コンストラクターと代入演算子は、コンパイラーによって生成された既定のバージョンとして引き続き提供されることに注意してください。

ビッグ 3 (または 5)を実装したくない場合にそれを回避するには、deleteそれらを明示的に実装する必要があります。

class String{
    public:
    int len;
    char *str;

    String()
    :len(0), str(nullptr){}

    String(char const* S)
    :len(strlen(S)), str(new char[len +1]){
        assert(S != 0);
        strcpy(str, S);
    }

    // Add these:
    String(const String&) = delete;
    String(String&&) = delete;
    String& operator=(const String&) = delete;
    String& operator=(String&&) = delete;

    ~String(){
        delete[]str;
    }
};
于 2016-04-20T17:39:41.777 に答える