2012-03-12 6 views
1

Я сделал несколько связанных списков раньше, и все концепции имеют смысл для меня, но для проекта я должен сделать шаблонный на C++, который я не использовал много, и У меня проблемы. Пожалуйста помоги. Я потратил слишком много времени на такую ​​простую вещь.C++ templated связанный список проблемы

У меня уже есть класс списка, но проблема здесь где-то здесь. Когда я делаю три узла в тесте и связать их все, если я называю

node1.getNext().show(); 

Это работает отлично, но если я

node1.getNext().getNext().show(); 

Я получаю Segfault (ядро сбрасывали). Что здесь не так? Я попытался изменить указатели на возвращаемые значения getNext() и getPrev() кучу раз без везения. Я чувствую себя глупо, задавая этот вопрос, но у меня серьезные проблемы. Мой класс узла ниже, а затем примерный тестовый пример, который дает segfault.

node.h:

template <class T> class Node 
{ 
public: 
    Node(); 
    Node(T value); 
    void setPrev(Node<T> node); 
    void setValue(T value); 
    void setNext(Node<T> node); 
    Node<T> getPrev(); 
    T getValue(); 
    Node<T> getNext(); 
    void show(); 
    ~Node() { } 

private: 
    Node<T> *prev; 
    Node<T> *next; 
    T value; 
}; 

//default construct                                      
template <class T> Node<T>::Node() { 
    this->prev = NULL; 
    this->value = NULL; 
    this->next = NULL; 
}; 

//overloaded construct                                     
template <class T> Node<T>::Node(T value) { 
    this->prev = NULL; 
    this->value = value; 
    this->next = NULL; 
} 

template <class T> void Node<T>::setPrev(Node<T> node) { 
    this->prev = &node; 
} 

template <class T> void Node<T>::setValue(T value) { 
    this->value = value; 
} 

template <class T> void Node<T>::setNext(Node<T> node) { 
    this->next = &node; 
} 

template <class T> Node<T> Node<T>::getPrev() { 
    return this->prev; 
} 

template <class T> T Node<T>::getValue() { 
    return this->value; 
} 

template <class T> Node<T> Node<T>::getNext() { 
    return this->next; 
} 

template <class T> 
void Node<T>::show() { 
    cout << value << endl; 
} 

Тестовый пример:

int main(int argc, char **argv) { 

    typedef Node<int> IntNode; 

    IntNode head(NULL); 
    IntNode node1(23); 
    IntNode node2(45); 
    IntNode node3(77); 
    IntNode tail(NULL); 
    node1.setPrev(head); 
    node1.setNext(node2); 
    node2.setPrev(node1); 
    node2.setNext(node3); 
    node3.setPrev(node2); 
    node3.setNext(tail); 

    node1.show(); 
    node2.show(); 
    node3.show(); 

    cout << node1.getNext().getValue() << endl; 
    cout << node1.getNext().getNext().getValue() << endl; 
} 
+1

Вы переопределяете 'std :: list' как учебный проект? –

+0

вместо этого на setPrev/setNext вы должны просто реализовать append и выполнить ссылки указателей внутри. В противном случае скрытие данных, то есть мотивация классов, неэффективно, будучи «жесткой» логикой, управляемой снаружи. – CapelliC

ответ

4

Вам необходимо передать значения по ссылке, а не по значению.

Когда ваш node1.setNext(node1) выполняется, setNext() получает копию node1 в стеке, а не переменная, которую определяют в main(). После выхода setNext() адрес, хранящийся в next, более недействителен.

Для начала переопределять функции setPrev и setNext в

template <class T> void Node<T>::setPrev(Node<T> &node) { 
    this->prev = &node; 
} 

template <class T> void Node<T>::setNext(Node<T> &node) { 
    this->next = &node; 
} 

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

+0

Большое спасибо. Как я уже сказал, я использовал только C++ несколько раз раньше, поэтому я пока не совсем доволен указателями, но работаю над этим. Еще раз спасибо! –

2

Вы должны хранить ваши следующей/предыдущей членов в качестве указателей. Когда вы устанавливаете свой предыдущий и следующий узлы, вы берете параметры по значению и, следовательно, копируете.

Это означает, что когда вы переходите ко второму .getNext() в node1.getNext().getNext().getValue(), вы столкнетесь с оборванным указателем, поэтому ваш код не работает.

Добавление узлов вручную трудоемко, как-то вроде std::list работает с помощью begin и указатель на свою коллекцию. Когда новый узел нажимается на передний или задний список, коллекция создает узел, сохраняет значение и связывает указатели, готовые к следующему узлу и/или обход.

1

Большая проблема в том, что ваши setNext и setPrev функции принимают свои параметры по значению, так что вы получите копию узлов вы объявляете в основном.

Если вы хотите продолжить это, передайте эти параметры по ссылке или указателем. Передача указателем, вероятно, будет более смысловой и предотвратит такую ​​случайную ошибку.