2017-12-19 2 views
0

이중 연결리스트 (대학 과제)에서 스마트 포인터를 구현하려고합니다. 그 전에 순수한 C에서 원시 포인터를 사용하여 동일한 작업을 수행했습니다. addNode()에 의해 List에 새 노드를 추가 할 때 두 번 이상 충돌이 발생합니다 (CodeLite (g ++), Windows 10 64 비트 사용). 문제는 내 메모리 관리 (노드 및 목록의 소멸자)라고 가정합니다. 그러나 나는 그것을 해결할 충분한 자격이 없다고 느낍니다. 그래서 어떤 도움을 주시면 감사하겠습니다.이중 연결리스트의 스마트 포인터

#include <stdlib.h> 
#include <iostream> 
#include <memory> 

using namespace std; 

template <typename T> 
struct Node  { 

    T Value; 
    weak_ptr<Node<T>> prev; 
    shared_ptr<Node<T>> next; 

    ~Node() { 
     while (next){ 
      prev = next->next; 
      next.reset(); 
      next = prev.lock(); 
     } 
    } 

}; 


template<typename T> 
class List 
{public: 

    shared_ptr<Node<T>> start; 
    weak_ptr<Node<T>> end; 
    int size; 

public: 
    List(): size(0){}; 
    ~List(); 

    void addNode (T value); 

}; 


template <typename T> List<T>::~List() 
{ 
    cout<<"List destructor"<<endl; 
    while (start){ 
     auto sp = end.lock(); 
     end = start->next; 
     start.reset(sp.get()); 
    } 
} 

template <typename T> void List<T>::addNode(T value){ 
    Node<T>* nd = new Node<T>; 

    if (size==0){ 
     start.reset(nd); 
     start->Value = value; 
     end = start; 

    } 

    else{ 
     auto sp = end.lock(); 
     auto sp2 = end.lock(); 
     sp->next.reset(nd); 
     sp.reset(sp->next.get()); 
     sp->prev = sp2; 
     sp->Value = value; 
     cout<<"Value size is "<<size<<" "<<sp->Value<<endl; 
     end = sp; 

    } 

    size++; 
    return; 
} 




int main() 
{ 
system("CLS"); 

    string a; 
    string b; 
    string c; 

    a = "1 test"; 
    b = "2 test"; 
    c = "3 test"; 


    List<string> ls; 
    ls.addNode(a); 
    ls.addNode(b); 
    ls.addNode(c); 

    return 0; 

} 
+0

여기에'shared_ptr' 필요하지 않습니다. 'unique_ptr'은 스마트 포인터를 원한다면 작업 도구입니다. – bolov

+2

이것은 무엇입니까? 'start.reset (sp.get());'와'sp.reset (sp-> next.get());'이것은 똑똑한 포인터를 다루는 완전히 잘못된 방법이다. – Slava

+0

@Slava 각각에 대해 오직 하나의 소유자가있다. 마디. 첫 번째 노드의 List 객체와 나머지 노드의 이전 노드입니다. Ergo'unique_ptr'이 사용되어야합니다. – bolov

답변

0

스마트 포인터를 사용하는 점은 자동 메모리 관리, 그래서 당신의 ListNode 소멸자뿐만 아니라 심하게 ​​구현뿐만 아니라 중복. 그냥 제거하거나 비워 두십시오. 당신이 경우하지 않은 (여러 가지 이유로 원시 포인터를 처리해야하는 경우에만, 당신은 스마트 포인터를 처리 할 때 일반적으로 당신이 reset()get() 메소드를 호출하지

template <typename T> void List<T>::addNode(T value){ 
    auto nd = std::make_shared<Node<T>>(); 
    nd->Value = value; // this should be done in Node constructor 

    if (size++ == 0){ 
     start = nd; 
    } else{ 
     auto sp = end.lock(); 
     nd->prev = sp; 
     sp->next = nd; 
    } 
    end = nd; 
} 

: 당신의 유일한 작업은 제대로 addNode()을 구현 할 수있다 이리).

참고 : 비 소멸자가 올바르게 작동하지만 재귀 호출로 인해 긴 목록에 문제가 발생할 수 있으므로 주석을 없애기 위해 List 소멸자 만 구현할 수 있습니다. 다시 말하지만 이것은 단지 일반적으로 스마트 포인터와 협력, reset()get()을 사용하지 않고 수행해야합니다 :

~List() 
{ 
    while(start) 
     start = start->next; 
} 
+0

O (n) 메모리를 사용하고 아마도 스택 오버플로 (이 사이트가 아닌 잘못된 종류)를 일으키는 대신 반복적으로 노드를 파괴하기 때문에 긴 목록에 대해서는 실제로 제대로 작동하지 않습니다. 이 문제를 해결하려면 목록에 대한 사용자 지정 소멸자가 필요하지만 매우 간단합니다. –

+0

이 솔루션이 긴 목록에 사용되는 것은 의심 스럽지만 분명히 숙제입니다. 어쨌든 소멸자는 나중에 프로그램을 구현할 때 추가 할 수 있으며 작은 목록에 대해서는 제대로 작동합니다. – Slava

+0

간단한 테스트 드라이버는'int main() {List l; for (int i = 0; i <1000000; ++ i) {l.addNode (i); }; 0을 반환;/* 큰 목록을 지원하는지 확인 * /}'. 나는 OP가 어떤 과정을 택하고 있는지, 또는 어디에 있는지는 모르지만, 이것이 나의 CS 과목들 중 하나에 숙제가 있다면, 그것이 시험 중 하나가 아니라면 나는 충격을받을 것입니다. (대부분의 구현의 스택 크기가 얼마인지 모르겠다. 백만 가지면 충분하지 않을 수도 있지만, 그 수를 늘리는 것은 쉽지 않다.) –