Nice programing

shared_ptr 및 weak_ptr 차이점

nicepro 2020. 11. 3. 19:14
반응형

shared_ptr 및 weak_ptr 차이점


Scott Meyers "Effective C ++"책을 읽고 있습니다. 내장 포인터 tr1::shared_ptr있고 tr1::weak_ptr그처럼 작동한다고 언급 되었지만 tr1::shared_ptrs, 객체를 가리키는 지점 수를 추적 합니다.

이를 참조 계수라고합니다. 이것은 비 tr1::shared_ptrs주기적 데이터 구조에서 리소스 누출을 방지하는 데 효과적이지만, 둘 이상의 객체 에주기가 형성되는 것과 같은 포함 된 경우주기에 대한 모든 외부 포인터가 파괴 된 경우에도주기가 서로의 참조 카운트를 0 이상으로 유지할 수 있습니다.

그것이 tr1::weak_ptrs들어오는 입니다.

내 질문은 순환 데이터 구조가 참조 횟수를 0 이상으로 만드는 방법입니다. 예제 C ++ 프로그램을 요청합니다. 문제는 어떻게 해결 weak_ptrs됩니까? (다시 예를 들어주세요).


A shared_ptr는 원시 포인터 주위에 참조 계수 메커니즘을 감 쌉니다. 따라서 shared_ptr참조 횟수 의 각 인스턴스에 대해 1 씩 증가합니다. share_ptr개체가 서로를 참조하면 참조 횟수가 0이되지 않으므로 삭제되지 않습니다.

weak_ptr를 가리 shared_ptr키지 만 참조 횟수를 늘리지는 않습니다. 즉, 참조가 있더라도 하위 개체를 삭제할 수 있습니다 weak_ptr.

이것이 작동하는 방식 은 기본 객체를 사용하고 싶을 때마다 for weak_ptr를 만드는 데 사용할 수 있다는 것 shared_ptr입니다. 그러나 객체가 이미 삭제 된 경우 a의 빈 인스턴스 shared_ptr가 반환됩니다. 기본 개체에 대한 참조 횟수가 참조로 증가하지 않기 때문에 weak_ptr순환 참조로 인해 기본 개체가 삭제되지 않습니다.


"제 질문, 순환 데이터 구조가 어떻게 참조 카운트를 0 이상으로 만드는지, 친절하게 C ++ 프로그램에서 예제와 함께 보여달라고 요청하십시오. 어떻게 문제가 weak_ptrs다시 예제를 통해 해결되는지 확인하십시오."

이 문제는 다음과 같은 C ++ 코드에서 발생합니다 (개념 상).

class A { shared_ptr<B> b; ... };
class B { shared_ptr<A> a; ... };
shared_ptr<A> x(new A);  // +1
x->b = new B;            // +1
x->b->a = x;             // +1
// Ref count of 'x' is 2.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, there will be a memory leak:
// 2 is decremented to 1, and so both ref counts will be 1.
// (Memory is deallocated only when ref count drops to 0)

질문의 두 번째 부분에 답하기 위해 : 참조 계산이주기를 처리하는 것은 수학적으로 불가능합니다. 따라서 a weak_ptr(기본적으로의 제거 된 버전 shared_ptr) 사이클 문제를 해결하는 데 사용할 수 없습니다 . 프로그래머가 사이클 문제를 해결하고 있습니다.

이를 해결하기 위해 프로그래머 는 객체 간의 소유권 관계를 알고 있어야 하거나 그러한 소유권이 자연적으로 존재하지 않는 경우 소유권 관계를 만들어야합니다.

위의 C ++ 코드는 A가 B를 소유하도록 변경할 수 있습니다.

class A { shared_ptr<B> b; ... };
class B { weak_ptr<A>   a; ... };
shared_ptr<A> x(new A); // +1
x->b = new B;           // +1
x->b->a = x;            // No +1 here
// Ref count of 'x' is 1.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, its ref count will drop to 0.
// While destroying it, ref count of 'x->b' will drop to 0.
// So both A and B will be deallocated.

중요한 질문은 다음과 같습니다. weak_ptr프로그래머가 소유권 관계를 말할 수없고 권한 부족 또는 정보 부족으로 인해 정적 소유권을 설정할 수없는 경우 사용할 수 있습니까?

대답은 다음과 같습니다. 객체 간의 소유권이 명확하지 weak_ptr 않으면 도움이 될 수 없습니다 . 사이클이 있다면 프로그래머는 그것을 찾아 깨뜨려야합니다. 대체 방법은 전체 가비지 수집 (예 : Java, C #, Go, Haskell)이있는 프로그래밍 언어를 사용하거나 C / C ++에서 작동하는 보수적 (= 불완전한) 가비지 수집기를 사용하는 것입니다 (예 : Boehm GC). .


미래의 독자를 위해.
Atom이 제공하는 설명이 훌륭하다는 것을 지적하고 싶습니다. 여기에 작업 코드가 있습니다.

#include <memory> // and others
using namespace std;

    class B; // forward declaration 
    // for clarity, add explicit destructor to see that they are not called
    class A { public: shared_ptr<B> b; ~A() {cout << "~A()" << endl; } };  
    class B { public: shared_ptr<A> a; ~B() {cout << "~B()" << endl; } };     
    shared_ptr<A> x(new A);  //x->b share_ptr is default initialized
    x->b = make_shared<B>(); // you can't do "= new B" on shared_ptr                      
    x->b->a = x;
    cout << x.use_count() << endl;  

Weak pointers just "observe" the managed object; they don't "keep it alive" or affect its lifetime. Unlike shared_ptr, when the last weak_ptr goes out of scope or disappears, the pointed-to object can still exist because the weak_ptr does not affect the lifetime of the object - it has no ownership rights. The weak_ptr can be used to determine whether the object exists, and to provide a shared_ptr that can be used to refer to it.

The definition of weak_ptr is designed to make it relatively foolproof, so as a result there is very little you can do directly with a weak_ptr. For example, you can't dereference it; neither operator* nor operator-> is defined for a weak_ptr. You can't access the pointer to the object with it - there is no get() function. There is a comparison function defined so that you can store weak_ptrs in an ordered container, but that's all.


All the above answer are WRONG. weak_ptr is NOT used to break cyclic references, they have another purpose.

Basically, if all shared_ptr(s) were created by make_shared() or allocate_shared() calls, you will NEVER need weak_ptr if you have no resource other than memory to manage. These functions create the shared_ptr reference counter object with the object itself, and the memory will be freed at the same time.

The only difference between weak_ptr and shared_ptr is that the weak_ptr allows the reference counter object to be kept after the actual object was freed. As a result, if you keep a lot of shared_ptr in a std::set the actual objects will occupy a lot of memory if they are big enough. This problem can be solved by using weak_ptr instead. In this case, you have to ensure the weak_ptr stored in the container is not expired before using it.

참고URL : https://stackoverflow.com/questions/4984381/shared-ptr-and-weak-ptr-differences

반응형