2016-10-19 1 views
1

연결된 목록에서 노드를 제거한 후 꼬리 원시 포인터를 새 꼬리로 업데이트하는 방법을 알아 내려고하고 있습니다. 내가C++ - 연결된 목록의 unique_ptr 노드에 원시 포인터 할당

std::unique_ptr<Node> head ; 
    Node* tail ; 

으로 나는 다음과 같은 구현을 뒤쪽에서 노드를 제거하는 내 함수에서 머리와 꼬리를 정의한

(숙제).

int Deque::remove_back(){ 
if (empty()) {throw std::runtime_error(std::string("Empty"));}; 

std::unique_ptr<Node> old; 

Node* p = head.get(); 

int return_value = tail->val; 

while (p->next != tail) 
{p = p->next)} 

old = move(tail); 
tail = p; 

return return_value; 
} 

그래서 꼬리는 유형 노드의 원시 포인터입니다. P는 Node 유형의 원시 포인터입니다.

Head는 Node 유형의 고유 한 포인터입니다.

나는 머리

P = P-> 다음에 P = head.get()

이제 P 점을 설정하고있어 내 노드를 반복해야합니다.

문제는 p->next != tail

P-> 다음은 어떤 페이지 다음 다음 노드에 대한 포인터는 것입니다.

node (tail) 유형의 원시 포인터와 같도록 노드에 대한 포인터를 설정하려고합니다.

나는 이것을 할 수 없다는 것을 알려줍니다.

나는 그것을 선언 한 관찰 대신에 소유 포인터로 바꾸지 않고 p-> 때문에 다음과 같이 생각합니다.

오류 :

Deque.cpp|68|error: no match for 'operator!=' (operand types are 'std::unique_ptr<Node>' and 'Node*')| 

Deque.cpp|69|error: cannot convert 'std::unique_ptr<Node>' to 'Node*' in assignment| 

Deque.cpp|71|error: no match for 'operator=' (operand types are 'std::unique_ptr<Node>' and 'std::remove_reference<Node*&>::type {aka Node*}')| 
+0

'꼬리 '를 사용 하시겠습니까? 그것은 전혀 도움이되지 않습니다. – Slava

+0

그래, 불행히도. : – TigerCode

+0

단일 링크 된 목록의'tail'은 목록 끝에있는 빠른 삽입에만 유용하지만 목록 끝에있는 빠른 제거에는 사용할 수 없기 때문에 쓸모 없습니다. –

답변

4

오류 메시지는 Node::nextstd::unique_ptr<Node> 것을 의미한다. std::unique_ptr을 원시 포인터에 직접 비교/할당 할 수 없습니다. 목록이 (head == tail)에서 단 1 노드가있는 경우 계정으로도

while (p->next.get() != tail) { 
    p = p->next.get(); 
} 

, 당신의 루프가 고려되지 않은 : 당신은 대신 std::unique_ptr::get() 방법을 사용해야합니다. p->next은 두 번째 반복에서 충돌이 발생하여 nullptr이됩니다. 목록의 마지막 노드를 제거 할 것이므로 headnullptr으로 재설정해야합니다. 어느 경우 든 p을 새 tail으로 지정할 때 p->nextnullptr으로 재설정해야 더 이상 이전 노드를 가리 키지 않습니다.

말했다되고 그건
int Deque::remove_back(){ 
    if (empty()) { 
     throw std::runtime_error("Empty"); 
    } 

    int return_value = tail->val; 

    if (!head->next) { 
     head = nullptr; // or: head.reset(); 
     tail = nullptr; 
    } 
    else { 
     Node* p = head.get(); 
     Node *prev = p; 
     while (p->next->next) { 
      p = p->next.get(); 
      prev = p; 
     } 
     tail = prev; 
     tail->next = nullptr; // or: tail->next.reset(); 
    } 

    return return_value; 
} 

, 그것은 연결된리스트의 구현에 std::unique_ptr을 사용하여 까다로운 일이 될 수 있습니다

이 시도해보십시오. 노드를 자동으로 삭제하려면 원시 포인터를 사용하고 자체가 파괴 된 노드를 파괴하는 클래스 내에서 목록을 래핑 한 다음 remove_back()은 제거 할 노드를 파괴 할 수 있습니다.

STL은 이미 std::list (이중 연결) 및 std::forward_list (단일 연결)과 같은 클래스를 사용할 수 있습니다.수동 목록 구현 대신 사용해야합니다.

+0

해당 사항 없음 숙제 등으로 스마트 포인터를 사용하기위한 구현의 이유와 장점을 고려하도록 많은 제한이 있습니다. – TigerCode

+1

"nullptr 옆에 p->를 재설정하지 않습니다."OP가 raw를 할당 할 수 없다는 것을 알게되면 수정 될 것입니다. 'std :: unique_ptr'에 대한 포인터. 올바르게 사용되면'std :: unique_ptr'을 사용하는 것이 합리적이라고 생각합니다. – Slava

+0

'std :: unique_ptr old;와'Node * Tail'을 서로 이동할 수 없습니다 – TigerCode

1

요소가 하나만있는 경우 문제가 발생합니다. 조건 (코드 중복으로)이 필요하거나 좀 더 복잡하게 만들 수 있습니다 :

int Deque::remove_back(){ 
    if (empty()) {throw std::runtime_error(std::string("Empty"));}; 

    Node *newtail = nullptr; 
    std::unique_ptr<Node> *curr = &head; 
    while(curr->get() != tail) { 
     newtail = curr->get(); 
     curr = &(*curr)->next; 
    } 

    tail = newtail; 
    std::unique_ptr<Node> tmp = std::move(*curr); 

    return tmp->val; 
} 
+0

나는 당신의 루프가 내 것보다 낫다. –