unique_ptr을 사용한 연결 목록의 팝 방법

Aug 20 2020

unique_ptron을 사용하여 단일 연결 목록의 구현을보고 있습니다 .https://solarianprogrammer.com/2019/02/22/cpp-17-implementing-singly-linked-list-smart-pointers/. 내 질문은 다음 방법과 관련이 있습니다.

 3 struct List {
 4     List() : head{nullptr} {};
 5 
 6     // ...
 7 
 8     void pop() {
 9         if(head == nullptr) {
10             return;
11         }
12 
13         std::unique_ptr<Node> temp = std::move(head);
14         head = std::move(temp->next);
15     }
16 
17     // ...
18 };

왜 여기에 임시가 필요한지 궁금합니다. 왜 단순히 할 수 head = std::move(head->next)없습니까? 메모리 누수가 발생하기 때문입니까? head재 할당 되면 unique_ptr현재 가리키는 메모리 가 자동으로 해제됩니까?

나는 스마트 포인터가 메모리 누수로부터 어리석은 증거라는 인상을 받았다. 이 경우 head더 이상 그것을 가리키는 스마트 포인터가 없기 때문에 원본에 대한 메모리 누수가있을 수 있습니까?

답변

4 RemyLebeau Aug 20 2020 at 07:36

왜 여기에 임시가 필요한지 궁금합니다.

실제로 필요 하지는 않지만 사용하는 것도 나쁘지 않습니다 .

왜 단순히 할 수 head = std::move(head->next)없습니까? 메모리 누수가 발생하기 때문입니까?

할 수 있습니다. 이 예에서는 누수가 없습니다.

head재 할당 되면 unique_ptr현재 가리키는 메모리 가 자동으로 해제됩니까?

예. 그러나 이전 포인터는 delete새 포인터의 소유권이 먼저 전송 될 때까지 'd 가 아닙니다 . cppreference 당 :

https://en.cppreference.com/w/cpp/memory/unique_ptr/operator%3D

에서 전송 소유권 r*this호출하여 마치 reset(r.release())의 할당 다음 get_deleter()에서 std::forward<E>(r.get_deleter()).

https://en.cppreference.com/w/cpp/memory/unique_ptr/reset

관리되는 개체를 바꿉니다.

  1. current_ptr에서 관리하는 포인터가 주어지면 *this이 순서대로 다음 작업을 수행합니다.

    1. 현재 포인터의 복사본을 저장합니다 old_ptr = current_ptr
    2. 현재 포인터를 인수로 덮어 씁니다. current_ptr = ptr
    3. 이전 포인터가 비어 있지 않은 경우 이전에 관리 된 개체를 삭제합니다
      if(old_ptr) get_deleter()(old_ptr).

그래서:

temp사용 하는 경우 이전 노드에 대한 포인터 head는 먼저 temp이동 생성자 를 통해 이동 head되며 nullptr. 그런 다음 해당 포인터를 head.operator=호출 next.release()하고 획득합니다. 그런 다음 temp범위를 벗어나 delete이전 노드를 사용합니다.

temp사용하지 않는 경우 head.operator=를 호출 next.release()하고 이전 포인터를 저장하고 해제 된 포인터로 교체 한 다음 delete저장된 포인터로 교체합니다 .

어느 쪽이든 누출이 없습니다.

나는 스마트 포인터가 메모리 누수로부터 어리석은 증거라는 인상을 받았다.

적절하게 사용 하면 예.

이 경우 head더 이상 그것을 가리키는 스마트 포인터가 없기 때문에 원본에 대한 메모리 누수가있을 수 있습니까?

누수가 없습니다. 항상 unique_ptr이전 노드에 대한 참조 가 있기 때문에 pop()종료되고 temp파괴 될 때까지 delete이전 노드와 함께 '이전 노드'를 사용합니다. 를 temp생략 하더라도 next포인터의 소유권 이 전송 된 후에도 이전 노드는 여전히 제대로 파괴됩니다 .