Рукописный связанный список - это segfaulting, и я не понимаю, почему - PullRequest
2 голосов
/ 12 марта 2010

Привет, я немного потрудился над созданием интерфейса для запуска gnuplot из c ++, и по какой-то причине реализация моего связного списка не удалась.

В приведенном ниже коде отсутствует строка plots->append(&plot). Проходя по коду, я обнаружил, что по какой-то причине деструктор ~John() вызывается сразу после конструктора John(), и я не могу понять почему.

Приведенный ниже код является урезанной версией, работающей только на Plot*. Первоначально я сделал связанный список как шаблон класса. И он прекрасно работал как ll<int> и ll<char*>, но по какой-то причине он не работает как ll<Plot*>.

Не могли бы вы помочь мне выяснить, почему это не удается? и, возможно, помочь мне понять, как заставить это работать?

Заранее: спасибо, куча!

// B2S

#include <string.h>

class Plot{
  char title[80];
public:
  Plot(){  }
};

class Link{
  Plot* element;
  Link* next;
  Link* prev;
  friend class ll;
};

class ll{
  Link* head;
  Link* tail;
public:
  ll(){
    head = tail = new Link();
    head->prev = tail->prev = head->next = tail->next = head;
  }
  ~ll(){
    while (head!=tail){
      tail = tail->prev;
      delete tail->next;
    }
    delete head;
  }
  void append(Plot* element){
    tail->element = element;
    tail->next = new Link();
    tail->next->prev = tail;
    tail->next = tail;
  }
};

class John{
  ll* plots;
public:
  John(){
   plots= new ll();
  }
  ~John(){
    delete plots;
  }
  John(Plot* plot){
    John();
    plots->append(plot);
  }
};   

int main(){
  Plot p;
  John k(&p);
}

Ответы [ 4 ]

2 голосов
/ 12 марта 2010

Потому что вы не можете вызывать альтернативные конструкторы в C ++. В ...

John(Plot* plot){
  John();
  plots->append(plot);
}

Ваша первая строка создает новый объект John, используя конструктор по умолчанию, а затем выбрасывает результат. Затем он вызывает append на plots (что, поскольку он не был установлен на что-либо, является мусором). Преобразуйте реальный код инициализации plots в закрытый метод, затем вызовите этот метод init в обоих конструкторах, прежде чем делать что-либо еще.

2 голосов
/ 12 марта 2010

утверждение:

 John();

Просто создает нового безымянного Иоанна, который был создан и немедленно уничтожен. В текущей версии C ++ нет способа вызвать конструктор из другого конструктора или уже созданного объекта.

Это означает, что plots член вашего John с именем k никогда не инициализируется, поэтому происходит сбой при вызове append из конструктора John.

[Как прокомментировал Нил Баттерворт, если вы на самом деле создали экземпляр ll, есть другие проблемы с ним, это просто самая насущная проблема.]

1 голос
/ 12 марта 2010
head = tail = new Link();

Здесь вы назначаете голову и хвост, чтобы указывать на один и тот же объект ссылки. Поскольку вы никогда не переназначаете ни одного из них, это означает, что каждый раз, когда вы меняете какое-либо свойство head (например, head.next = foo), то же самое изменение применяется к tail.

Значение головы и хвоста всегда будет иметь один и тот же элемент, предшественник и один и тот же преемник. Очевидно, это не приводит к намеченным результатам.

0 голосов
/ 12 марта 2010
  Plot p;
  John k(&p);

Используйте это вместо:

  Plot * p = (Plot*) new Plot;
  John k(p);

Этот код не работает, поскольку после выхода p из области видимости, ссылка k на него умрет. Это не ошибка, которая вызвала segfault, но, вероятно, позже она вызовет segfault, как только вы исправите другие ошибки.

Вам нужно будет удалить p позже.

...