문제

boost :: shared_ptr을 삭제하지 않고 저장된 포인터를 릴리스 할 수 있습니까?

문서에는 릴리스 기능이 존재하지 않으며 FAQ에서도 릴리스 기능을 제공하지 않는 이유에 대해 설명합니다. 릴리스는 독특하지 않은 포인터에서 릴리스를 수행 할 수 없습니다. 내 포인터는 독특합니다. 포인터를 어떻게 해제 할 수 있습니까? 또는 어떤 부스트 스마트 포인터 클래스를 사용하여 포인터를 출시 할 수 있습니까? 나는 당신이 auto_ptr을 사용한다고 말하지 않기를 바랍니다. :)

도움이 되었습니까?

해결책

기본 포인터를 삭제하지 말라고 요청할 수있는 델리터를 사용해야합니다.

이 답변을 참조하십시오 자세한 내용은 (이 질문의 복제물로 표시되었습니다).

다른 팁

하지 않다. 부스트의 FAQ 항목 :

. shared_ptr이 release () 함수를 제공하지 않는 이유는 무엇입니까?

. shared_ptr 다른 사본이 여전히 객체를 파괴하기 때문에 고유 한 ()이 아니라면 소유권을 포기할 수 없습니다.

고려하다:

shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2

int * p = a.release();

// Who owns p now? b will still call delete on it in its destructor.

또한, release ()에 의해 반환 된 포인터는 shared_ptr 소스가 사용자 정의 델리터로 생성 될 수 있으므로 안정적으로 거래하기가 어려울 것입니다.

따라서, 이것은 객체 (고유 한 ()가 true를 반환 할 때)를 가리키는 유일한 shared_ptr 인스턴스 인 경우에도 안전합니다. 그러한 .release () 함수를 사용한 경우에도 여전히 귀하의 디자인에 의문을 제기합니다.

가짜 델리터를 사용할 수 있습니다. 그러면 포인터는 실제로 삭제되지 않습니다.

struct NullDeleter {template<typename T> void operator()(T*) {} };

// pp of type some_t defined somewhere
boost::shared_ptr<some_t> x(pp, NullDeleter() );

아이들, 집에서는 이것을하지 마십시오.

// set smarty to point to nothing
// returns old(smarty.get())
// caller is responsible for the returned pointer (careful)
template <typename T>
T* release (shared_ptr<T>& smarty) {
    // sanity check:
    assert (smarty.unique());
    // only one owner (please don't play games with weak_ptr in another thread)
    // would want to check the total count (shared+weak) here

    // save the pointer:
    T *raw = &*smarty;
    // at this point smarty owns raw, can't return it

    try {
        // an exception here would be quite unpleasant

        // now smash smarty:
        new (&smarty) shared_ptr<T> ();
        // REALLY: don't do it!
        // the behaviour is not defined!
        // in practice: at least a memory leak!
    } catch (...) {
        // there is no shared_ptr<T> in smarty zombie now
        // can't fix it at this point:
        // the only fix would be to retry, and it would probably throw again
        // sorry, can't do anything
        abort ();
    }
    // smarty is a fresh shared_ptr<T> that doesn't own raw

    // at this point, nobody owns raw, can return it
    return raw;
}

이제 심판 수에 대한 총 소유자 수가> 1인지 확인하는 방법이 있습니까?

포인터가 다시는 아무것도 가리킬 수 있도록 shared_ptr::reset().

그러나 이것은 포인터가 객체에 대한 마지막 참조 일 때를 가리키는 객체를 삭제합니다. 그러나 이것은 처음부터 스마트 포인터의 원하는 동작입니다.

객체를 살아 있지 않은 참조를 원한다면 boost::weak_ptr (보다 문서를 높이십시오). ㅏ weak_ptr 객체에 대한 참조를 보유하고 있지만 참조 수에 추가되지 않으므로 약한 참조 만 존재하면 객체가 삭제됩니다.

공유의 기초는 신뢰입니다. 프로그램의 일부 인스턴스가 원시 포인터를 해제 해야하는 경우 거의 확실합니다. shared_ptr 잘못된 유형입니다.

그러나 최근에 나는 다른 프로세스에서 거래해야했기 때문에 이것도하고 싶었습니다. 결국 나는 일부를 사용하기로 한 나의 오래된 결정을 배웠습니다. std::shared_ptr 생각이 아니었다.

나는 정기적 으로이 유형을 정리하기 위해 사용했습니다. 그러나 포인터는 몇 곳에서 복제되었습니다. 실제로 나는 필요했다 std::unique_ptr, (우연히)가 있습니다 release 기능.

그들이 무엇을하는지 알지 못하기 때문에 그들을 용서하십시오. 이 예제는 Memory Leaks없이 boost :: shared_ptr 및 msvs std :: shared_ptr에서 작동합니다!

template <template <typename> class TSharedPtr, typename Type>
Type * release_shared(TSharedPtr<Type> & ptr)
{
    //! this struct mimics the data of std:shared_ptr ( or boost::shared_ptr )
    struct SharedVoidPtr
    {
        struct RefCounter
        {
            long _Uses;
            long _Weaks;
        };

        void * ptr;
        RefCounter * refC;

        SharedVoidPtr()
        {
            ptr = refC = nullptr;
        }

        ~SharedVoidPtr()
        {
            delete refC;
        }
    };

    assert( ptr.unique() );

    Type * t = ptr.get();

    SharedVoidPtr sp; // create dummy shared_ptr
    TSharedPtr<Type> * spPtr = (TSharedPtr<Type>*)( &sp );
    spPtr->swap(ptr); // swap the contents

    ptr.reset();
    // now the xxx::shared_ptr is empy and
    // SharedVoidPtr releases the raw poiter but deletes the underlying counter data
    return t;
}

공유 포인터를 삭제할 수 있습니다. 포인터가 항상 독특하다면 std::auto_ptr<> 좋은 선택입니다. STL 컨테이너에는 고유 한 포인터를 사용할 수 없습니다. 작업에 대한 작업은 많은 복사 및 임시 복제를 수행하므로 고유 한 포인터를 사용할 수 없습니다.

나는 당신의 질문이 이것을 달성하는 것에 관한 것인지 완전히 확신하지 못하지만 당신이 shared_ptr, 여기서, 당신이 하나에서 값을 해제하면 shared_ptr, 동일한 값에 대한 다른 모든 공유 포인터는 NULLPTR이되면 unique_ptr 안에 shared_ptr 그 행동을 달성하기 위해.

void print(std::string name, std::shared_ptr<std::unique_ptr<int>>& ptr)
{
    if(ptr == nullptr || *ptr == nullptr)
    {
        std::cout << name << " points to nullptr" << std::endl;
    }
    else
    {
        std::cout << name << " points to value " << *(*ptr) << std::endl;
    }
}

int main()
{
    std::shared_ptr<std::unique_ptr<int>> original;
    original = std::make_shared<std::unique_ptr<int>>(std::make_unique<int>(50));

    std::shared_ptr<std::unique_ptr<int>> shared_original = original;

    std::shared_ptr<std::unique_ptr<int>> thief = nullptr;

    print(std::string("original"), original);
    print(std::string("shared_original"), shared_original);
    print(std::string("thief"), thief);

    thief = std::make_shared<std::unique_ptr<int>>(original->release());

    print(std::string("original"), original);
    print(std::string("shared_original"), shared_original);
    print(std::string("thief"), thief);

    return 0;
}

산출:

original points to value 50
shared_original points to value 50
thief points to nullptr
original points to nullptr
shared_original points to nullptr
thief points to value 50

이 동작을 사용하면 배열과 같은 리소스를 공유 한 다음 나중에 해당 리소스를 재사용 하면서이 리소스에 대한 모든 공유 참조를 무효화합니다.

다음은 작동 할 수있는 해킹이 있습니다. 당신이 진짜 구속력이 없다면 나는 그것을 추천하지 않을 것입니다.

template<typename T>
T * release_shared(std::shared_ptr<T> & shared)
{
    static std::vector<std::shared_ptr<T> > graveyard;
    graveyard.push_back(shared);
    shared.reset();
    return graveyard.back().get();
}

당신의 포인터가 실제로 독특하다면 사용합니다 std::unique_ptr 또는 boost::scoped_ptr 전자가 컴파일러에 사용할 수없는 경우. 그렇지 않으면 사용을 결합하는 것을 고려하십시오 boost::shared_ptr ~와 함께 boost::weak_ptr. 확인하십시오 문서를 높이십시오 자세한 내용은.

POCO :: httpRequestHandlerFactory를 사용하여 RAW HTTPREQUESTHANDLER*를 반환 할 것으로 예상합니다. POCO 프레임 워크는 요청이 완료되면 처리기를 삭제합니다.

또한 DI 소스 프로젝트를 사용하여 컨트롤러를 생성하지만 직접 반환 할 수없는 Shared_ptr을 반환하고 handler.get ()을 반환하면이 함수가 범위를 벗어나 삭제 한 다음 handler가 삭제되기 때문에 handler.get ()는 좋지 않습니다. 실행되기 전에. release () 방법을 갖는 합리적인 (생각) 이유가 있습니다. 다음과 같이 httprequesthandlerwrapper 클래스를 만들었습니다.

class HTTPRequestHandlerWrapper : public HTTPRequestHandler {
private:
    sauce::shared_ptr<HTTPRequestHandler> _handler;

public:
    HTTPRequestHandlerWrapper(sauce::shared_ptr<HTTPRequestHandler> handler) {
        _handler = handler;
    }

    virtual void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) {
        return _handler->handleRequest(request, response);
    }
};

그리고 공장은 그랬습니다

HTTPRequestHandler* HttpHandlerFactory::createRequestHandler(const HTTPServerRequest& request) {
    URI uri = URI(request.getURI());
    auto path = uri.getPath();
    auto method = request.getMethod();

    sauce::shared_ptr<HTTPRequestHandler> handler = _injector->get<HTTPRequestHandler>(method + ":" + path);

    return new HTTPRequestHandlerWrapper(handler);
}

소스와 포코를 모두 만족시키고 잘 작동합니다.

비동기 핸들러를 통해 포인터를 전달하고 실패의 경우 자체 파괴 동작을 유지해야했지만 최종 API는 원시 포인터를 예상 했으므로이 기능을 단일 shared_ptr에서 해제하도록했습니다.

#include <memory>

template<typename T>
T * release(std::shared_ptr<T> & ptr)
{
    struct { void operator()(T *) {} } NoDelete;

    T * t = nullptr;
    if (ptr.use_count() == 1)
    {
        t = ptr.get();
        ptr.template reset<T>(nullptr, NoDelete);
    }
    return t;
}

만약에 ptr.use_count() != 1 당신은 얻을 것입니다 nullptr 대신에.

쉬운 솔루션, 기준을 늘린 다음 shared_pointer를 누출하십시오.

boost::shared_ptr<MyType> shared_pointer_to_instance(new MyType());
new boost::shared_ptr<MyType>();
MyType * raw_pointer = shared_pointer_to_instance.get()

이것은 분명히 shared_ptr과 mytype의 메모리 누출을 유발합니다 *

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top