program story

shared_ptr 인 이유

inputbox 2020. 9. 10. 07:48
반응형

shared_ptr 인 이유 legal, while unique_ptr 잘못된 형태입니까?


질문은 제목에 정말 적합합니다.이 차이에 대한 기술적 이유가 무엇인지 알고 싶은데 그 이유도 궁금합니다.

std::shared_ptr<void> sharedToVoid; // legal;
std::unique_ptr<void> uniqueToVoid; // ill-formed;

이 때문에 인 std::shared_ptr반면, 구현 형 삭제 std::unique_ptr하지 않습니다.


std::shared_ptr유형 삭제를 구현 하기 때문에 또 다른 흥미로운 속성 인 viz 도 지원합니다 . 클래스 템플릿에 대한 템플릿 유형 인수로 삭제 자의 유형이 필요 하지 않습니다 . 그들의 선언을보십시오 :

template<class T,class Deleter = std::default_delete<T> > 
class unique_ptr;

이는 보유 Deleter하면서, 입력 파라미터로서

template<class T> 
class shared_ptr;

없습니다.

이제 질문은 왜 shared_ptr유형 삭제를 구현합니까? 음, 그렇게합니다. 참조 카운팅을 지원해야하고이를 지원하기 위해 힙에서 메모리를 할당해야 하고 어쨌든 메모리 할당해야하므로 한 단계 더 나아가 유형 삭제를 구현합니다. 이는 힙이 필요합니다. 할당도. 그래서 기본적으로 그것은 단지 기회 주의적입니다!

유형 삭제로 인해는 std::shared_ptr두 가지를 지원할 수 있습니다.

  • 이 같은 유형의 객체를 저장할 수 있습니다 void*, 하지만 여전히 제대로 파괴에 개체를 삭제할 수 있습니다 올바르게에 의해 자신의 소멸자를 호출 .
  • deleter의 유형은 클래스 템플릿에 유형 인수로 전달되지 않으므로 type-safety를 손상시키지 않고 약간의 자유를 의미합니다 .

좋구나. 그것이 std::shared_ptr작동 방식 에 관한 것 입니다.

이제 질문은 std::unique_ptr객체 저장할 void*있습니까? 음, 대답은 그렇습니다 . 적절한 삭제자를 인수로 전달했다면 그렇습니다 . 다음은 그러한 데모 중 하나입니다.

int main()
{
    auto deleter = [](void const * data ) {
        int const * p = static_cast<int const*>(data);
        std::cout << *p << " located at " << p <<  " is being deleted";
        delete p;
    };

    std::unique_ptr<void, decltype(deleter)> p(new int(959), deleter);

} //p will be deleted here, both p ;-)

출력 ( 온라인 데모 ) :

959 located at 0x18aec20 is being deleted

댓글에 매우 흥미로운 질문을했습니다.

제 경우에는 유형 지우기 삭제자가 필요하지만 가능해 보입니다 (일부 힙 할당 비용). 기본적으로 이것은 실제로 세 번째 유형의 스마트 포인터에 대한 틈새 지점이 있음을 의미합니까 : 유형 삭제가있는 독점 소유권 스마트 포인터입니다.

이는에 @ 스티브 Jessop는 다음과 같은 솔루션을 제안,

나는 실제로 이것을 시도한 적이 없지만 아마도 당신은 적절한 것을 삭제 자 std::function유형으로 사용하여 얻을 수 unique_ptr있습니까? 실제로 작동한다고 가정하면 독점 소유권과 유형 삭제 삭제가 완료됩니다.

이 제안에 따라 이것을 구현했습니다 ( std::function필요하지 않은 것처럼 사용 하지는 않지만).

using unique_void_ptr = std::unique_ptr<void, void(*)(void const*)>;

template<typename T>
auto unique_void(T * ptr) -> unique_void_ptr
{
    return unique_void_ptr(ptr, [](void const * data) {
         T const * p = static_cast<T const*>(data);
         std::cout << "{" << *p << "} located at [" << p <<  "] is being deleted.\n";
         delete p;
    });
}

int main()
{
    auto p1 = unique_void(new int(959));
    auto p2 = unique_void(new double(595.5));
    auto p3 = unique_void(new std::string("Hello World"));
}  

출력 ( 온라인 데모 ) :

{Hello World} located at [0x2364c60] is being deleted.
{595.5} located at [0x2364c40] is being deleted.
{959} located at [0x2364c20] is being deleted.

도움이 되었기를 바랍니다.


이론적 근거 중 하나는 a의 많은 사용 사례 중 하나에 있습니다. shared_ptr즉, 수명 지표 또는 보초로 사용됩니다.

이것은 원래의 부스트 문서에서 언급되었습니다.

auto register_callback(std::function<void()> closure, std::shared_ptr<void> pv)
{
    auto closure_target = { closure, std::weak_ptr<void>(pv) };
    ...
    // store the target somewhere, and later....
}

void call_closure(closure_target target)
{
    // test whether target of the closure still exists
    auto lock = target.sentinel.lock();
    if (lock) {
        // if so, call the closure
        target.closure();
    }
}

closure_target다음과 같은 것이 어디에 있습니까?

struct closure_target {
    std::function<void()> closure;
    std::weak_ptr<void> sentinel;
};

호출자는 다음과 같은 콜백을 등록합니다.

struct active_object : std::enable_shared_from_this<active_object>
{
    void start() {
      event_emitter_.register_callback([this] { this->on_callback(); }, 
                                       shared_from_this());
    }

    void on_callback()
    {
        // this is only ever called if we still exist 
    }
};

because shared_ptr<X> is always convertible to shared_ptr<void>, the event_emitter can now be blissfully unaware of the type of object it is calling back into.

This arrangement releases subscribers to the event emitter of the obligation of handling crossing cases (what if the callback in on a queue, waiting to be actioned while active_object goes away?), and also means that there is no need to synchronise unsubscription. weak_ptr<void>::lock is a synchronised operation.

참고URL : https://stackoverflow.com/questions/39288891/why-is-shared-ptrvoid-legal-while-unique-ptrvoid-is-ill-formed

반응형