Pergunta

Boost::shared_ptr pode liberar o ponteiro armazenado sem excluí-lo?

Posso ver que não existe nenhuma função de liberação na documentação, também no FAQ é explicado porque ele não fornece a função de liberação, algo assim o lançamento não pode ser feito em ponteiros que não são exclusivos.Minhas dicas são únicas.Como posso liberar meus ponteiros?Ou qual classe de ponteiro inteligente de impulso usar que me permitirá liberar o ponteiro?Espero que você não diga para usar auto_ptr :)

Foi útil?

Solução

Você precisa usar um delete que possa solicitar para não excluir o ponteiro subjacente.

Veja esta resposta (que foi marcado como uma duplicata dessa questão) para obter mais informações.

Outras dicas

Não. Entrada de perguntas frequentes do Boost:

Q. Por que Shared_Ptr fornece uma função de release ()?

UMA. shared_ptr Não pode doar a propriedade, a menos que seja exclusiva () porque a outra cópia ainda destruirá o objeto.

Considerar:

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.

Além disso, o ponteiro retornado por release () seria difícil de desalocar de maneira confiável, pois a fonte compartilhada_ptr poderia ter sido criada com um deleter personalizado.

Portanto, isso seria seguro, caso seja a única instância Shared_PTR apontando para o seu objeto (quando exclusivo () retorna verdadeiro) e o objeto não requer um deleter especial. Eu ainda questionaria seu design, se você usasse uma função .release ().

Você pode usar o deleter falso. Então os ponteiros não serão excluídos, na verdade.

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

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

Crianças, não faça isso em casa:

// 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;
}

Agora, existe uma maneira de verificar se a contagem total dos proprietários para a contagem de ref é> 1?

Para deixar o ponteiro apontar para nada de novo, você pode ligar shared_ptr::reset().

No entanto, isso excluirá o objeto apontado quando seu ponteiro for a última referência ao objeto. Este, no entanto, é exatamente o comportamento desejado do ponteiro inteligente em primeiro lugar.

Se você deseja apenas uma referência que não segure o objeto vivo, você pode criar um boost::weak_ptr (Vejo Boost Documentation). UMA weak_ptr Mantenha uma referência ao objeto, mas não adiciona à contagem de referência, portanto o objeto é excluído quando apenas referências fracas existem.

A base do compartilhamento é a confiança. Se alguma instância do seu programa precisa liberar o ponteiro bruto, é quase com certeza que shared_ptr é do tipo errado.

No entanto, recentemente, eu também queria fazer isso, pois precisava desalpor de um processo diferente. No final, fui ensinado que minha decisão mais antiga de usar alguns std::shared_ptr não foi pensado.

Eu apenas usei rotineiramente esse tipo para limpeza. Mas o ponteiro foi duplicado em alguns lugares. Na verdade eu precisava de um std::unique_ptr, que (surpresa) tem um release função.

Perdoe -os porque eles não sabem o que fazem. Este exemplo funciona com o boost :: shared_ptr e msvs std :: shared_ptr sem vazamentos de memória!

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;
}

Você pode excluir o ponteiro compartilhado, que parece o mesmo para mim.Se os ponteiros são sempre únicos, então std::auto_ptr<> é uma boa escolha.Tenha em mente que ponteiros exclusivos não podem ser usados ​​em contêineres STL, pois as operações neles fazem muitas cópias e duplicações temporárias.

Não tenho muita certeza se sua pergunta é conseguir isso, mas se você deseja comportamento de um shared_ptr, onde, se você liberar o valor de um shared_ptr, todos os outros ponteiros compartilhados para o mesmo valor se tornam um nullptr, então você pode colocar um unique_ptr em um shared_ptr para alcançar esse comportamento.

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;
}

Resultado:

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

Esse comportamento permite que você compartilhe um recurso (como uma matriz) e depois reutilize esse recurso enquanto invalida todas as referências compartilhadas a esse recurso.

Aqui está um hack que pode funcionar. Eu não recomendaria a menos que você esteja em um vínculo real.

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();
}

Se seus ponteiros são realmente únicos, use std::unique_ptr ou boost::scoped_ptr Se o primeiro não estiver disponível para o seu compilador. Caso contrário, considere combinar o uso de boost::shared_ptr com boost::weak_ptr. Confira o Boost Documentation para detalhes.

Estou usando o poco :: httprequestHandlerFactory, que espera retornar um httprequestHandler bruto*, a estrutura POCO exclui o manipulador assim que a solicitação terminar.

Também usando o projeto de molho DI para criar os controladores, no entanto, o injetor retorna compartilhado_ptr que não posso retornar diretamente, e o retorno do manipulador.get () também não é bom, pois o mais rápido que essa função retorna, o shared_ptr sai do escopo e exclui o manipulador e depois o manipulador Antes de ser executado, então aqui está um motivo razoável (eu acho) para ter um método .release (). Acabei criando uma classe httprequesthandlerwrapper da seguinte maneira:-

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);
    }
};

E então a fábrica iria

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);
}

que satisfez o molho e o poco e funciona bem.

Eu precisava passar um ponteiro através de manipuladores de assíncronos e manter o comportamento de autodestruir em caso de falha, mas a API final esperava um ponteiro bruto, então fiz essa função para liberar de um único 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;
}

Se ptr.use_count() != 1 Você deve conseguir um nullptr em vez de.

Solução fácil, aumente a referência e vaze o 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()

Isso causará claramente um vazamento de memória do Shared_Ptr e do MyType *

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top