2012-03-12 2 views
1

이전에 몇 개의 링크 된 목록을 만들었으며 개념이 모두 나에게 의미가 있지만 프로젝트의 경우 C++로 템플릿을 만들어야합니다. 나는 곤경에 처해있다. 도와주세요. 나는 그런 간단한 일에 너무 많은 시간을 보냈습니다.C++ templated linked list trouble

이미 목록 클래스 중 일부가 있지만 문제는 여기 어딘가에 있습니다. 나는 테스트 케이스에 세 개의 노드를하고 내가 잘 작동

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 사본을 스택에 가져옵니다. 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; 
} 

로하고는 즉시 세그먼테이션 폴트 (segfault)를 수정합니다. 그러나 코드의 디자인과 참조 또는 값으로 전달할 때 올바르게 작성하고 추가 문제를 피하는 방법에 대해 더 많이 생각해야합니다.

+0

고마워요. 내가 말했듯이, 나는 단지 몇 번 전에 C++을 사용했기 때문에, 아직 포인터에 대해서는 완전히 안락하지만, 그것에 대해 연구하고있다. 다시 한 번 감사드립니다! –

2

. 이전 노드와 다음 노드를 설정할 때 값으로 매개 변수를 가져와 복사합니다.

즉, node1.getNext().getNext().getValue()에있는 두 번째 .getNext()까지 단계적으로 이동하면 매달리는 포인터가 생겨 코드가 실패하는 것입니다.

노드를 손으로 추가하는 것은 번거롭기 때문에 std::list과 같은 방식은 beginend이 소유 한 컬렉션에 대한 포인터를 갖는 것입니다. 새로운 노드가리스트의 앞이나 뒤쪽으로 밀리면 콜렉션은 노드를 생성하고, 값을 저장하고 다음 노드 및/또는 순회를 위해 준비된 포인터를 연결합니다.

1

큰 문제는 당신이 당신이 메인에 선언 노드의 복사 얻을 귀하의 setNextsetPrev 기능, 값으로 자신의 매개 변수를 사용한다는 것입니다.

이 작업을 계속하려면 이러한 매개 변수를 참조 또는 포인터로 전달하십시오. 포인터를 건네면 더 의미 론적 인 의미를 갖게되고 우발적 인 실수를 예방할 수 있습니다.