Domanda

Può boost :: shared_ptr rilasciare il puntatore memorizzato senza eliminarlo?

Non vedo funzione di rilascio esiste nella documentazione, anche nelle FAQ si spiega il motivo per cui non fornisce funzione di rilascio, qualcosa di simile che il rilascio non può essere fatto su puntatori che non sono unici. I miei puntatori sono unici. Come posso rilasciare il mio puntatori? O che aumentare la classe di puntatore intelligente da usare che mi permetterà il rilascio del puntatore? Spero che tu non dirai uso auto_ptr:)

È stato utile?

Soluzione

È necessario utilizzare un deleter che è possibile richiedere di non eliminare il puntatore sottostante.

Vedere questa risposta (che è stato contrassegnato come un duplicato di questo problema) per ulteriori informazioni.

Altri suggerimenti

Non farlo. voce delle FAQ di Boost:

  

Q . Perché non shared_ptr fornire una funzione di rilascio ()?

     

A . shared_ptr non può dare via proprietà meno che non sia unico (), perché l'altra copia sarà ancora distruggere l'oggetto.

     

Si consideri:

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.
     

Inoltre, il puntatore restituito da release () sarebbe difficile da rilasciare in modo affidabile, come lo shared_ptr fonte potrebbe essere stato creato con un deleter personalizzato.

Quindi, questo sarebbe al sicuro nel caso in cui è l'unico caso shared_ptr indicando l'oggetto (quando univoco () restituisce vero) e l'oggetto non richiede un deleter speciale. Sarei ancora in discussione il vostro disegno, se è stato utilizzato una funzione tale .Rilasciare ().

Si potrebbe utilizzare deleter falso. Allora puntatori non verranno cancellati in realtà.

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

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

I bambini, non farlo a 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;
}

Ora, c'è un modo per verificare se il conteggio totale dei proprietari per il conteggio ref è> 1?

Per consentire il punto puntatore a nulla di nuovo, è possibile chiamare shared_ptr::reset().

Tuttavia, questo cancellerà l'oggetto puntato quando il puntatore è l'ultimo riferimento all'oggetto. Questo comportamento tuttavia, è esattamente la desiderata del puntatore intelligente in primo luogo.

Se si desidera solo un riferimento che non tiene in vita l'oggetto, è possibile creare un boost::weak_ptr (vedi spinta documentazione ). Un weak_ptr contiene un riferimento all'oggetto, ma non aggiunge al conteggio di riferimento, in modo da l'oggetto viene eliminato quando esistono solo riferimenti deboli.

La base della condivisione è la fiducia. Se qualche esempio nel vostro programma deve rilasciare il puntatore grezzo, è quasi per certo che shared_ptr è il tipo sbagliato.

Tuttavia, di recente ho voluto fare anche questo, come ho bisogno di rilasciare da un diverso processo-mucchio. Alla fine mi è stato insegnato che la mia decisione più anziani di usare alcuni std::shared_ptr non è stato pensato-out.

Ho appena abitualmente usato questo tipo per la pulizia. Ma il puntatore era appena duplicato su un paio di posti. In realtà ho bisogno di un std::unique_ptr, che (sorpresa) ha una funzione release.

Perdona loro perché non sanno quello che fanno. Questo esempio funziona con boost :: shared_ptr e MSVS std :: shared_ptr senza perdite di memoria!

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

È possibile eliminare il puntatore condiviso, che sembra più o meno lo stesso per me. Se i puntatori sono sempre unici, allora std::auto_ptr<> è una buona scelta. Tenete a mente che i puntatori uniche non possono essere utilizzati in contenitori STL, dal momento che le operazioni su di essi fanno un sacco di copia e la duplicazione temporanea.

Non sono del tutto sicuro se la tua domanda è di circa il raggiungimento di questo, ma se si vuole un comportamento da un shared_ptr, dove, se si rilascia il valore da un shared_ptr, tutti gli altri indicatori condivisi per lo stesso valore di diventare un nullptr, allora si può mettere un unique_ptr in un shared_ptr per raggiungere tale 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;
}

Output:

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

Questo comportamento consente di condividere una risorsa (come un array), poi riutilizzare quella risorsa, mentre invalidare tutti i riferimenti condivisi a questa risorsa.

Ecco un hack che potrebbe funzionare. Io non lo consiglio a meno che non sei in un vicolo cieco reale.

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 i puntatori sono davvero unici utilizzati std::unique_ptr o boost::scoped_ptr se la prima non è disponibile per il vostro compilatore. Altrimenti considerare combinando l'uso di boost::shared_ptr con boost::weak_ptr. Controlla la Boost documentazione per i dettagli.

Sto usando Poco :: HTTPRequestHandlerFactory che prevede di restituire un HTTPRequestHandler grezzo *, il quadro Poco cancella il gestore di una volta che la richiesta di finiture.

Anche utilizzando Project di salsa per creare i controllori, tuttavia l'iniettore ritorna shared_ptr che non posso tornare direttamente, e tornando handler.get () è non va bene né in quanto la non appena questa funzione restituisce lo shared_ptr va fuori del campo di applicazione e cancella poi handler prima della sua giustiziati, ecco un ragionevole (credo) motivo per avere un metodo .Rilasciare (). Ho finito per creare una classe HTTPRequestHandlerWrapper come segue: -

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 quindi la fabbrica sarebbe

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

che soddisfaceva entrambi salsa e Poco e funziona bene.

avevo bisogno di passare attraverso un puntatore gestori asincroni e per mantenere il comportamento autodistruzione in caso di fallimento, ma API finale previsto un puntatore non elaborato, così ho fatto questa funzione per liberare da un unico 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 si deve ottenere un nullptr invece.

Soluzione facile, aumentare il riferimento e quindi perdita del 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()

In questo modo chiaramente causare una perdita di memoria sia del shared_ptr e MyType *

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top