Frage

Kann boost :: shared_ptr die gespeicherte Zeiger freigeben, ohne sie zu löschen?

kann ich keine Freigabefunktion besteht in der Dokumentation sehen, die auch in der FAQ erklärt, warum es nicht Release-Funktion zur Verfügung stellen, wie etwas, dass die Freigabe kann nicht auf Zeiger erfolgen, die nicht eindeutig sind. Meine Zeiger sind einzigartig. Wie kann ich meine Zeiger freigeben? Oder die Steigerung der Smart-Pointer-Klasse zu verwenden, die ich des Zeigers Freigabe ermöglicht? Ich hoffe, dass Sie nicht verwenden auto_ptr sagen:)

War es hilfreich?

Lösung

Sie benötigen einen deleter verwenden, die Sie anfordern können, die die zugrunde liegenden Zeiger zu löschen.

Sehen Sie diese Antwort (wur als Duplikat dieser Frage markiert) für weitere Informationen.

Andere Tipps

Nicht. Erhöhung der FAQ-Eintrag:

  

F . Warum Shared_ptr kein Release () Funktion zur Verfügung stellen?

     

A . shared_ptr kann nicht Eigentum verschenken, wenn es eindeutig ist (), weil die andere Kopie wird nach wie vor das Objekt zerstören.

     

Bedenken Sie:

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.
     

Darüber hinaus wird der Zeiger durch Freigabe () zurückgegeben würde schwierig sein, zuverlässig freizugeben, als die Quelle shared_ptr mit einem benutzerdefinierten deleter erstellt werden konnte.

So würde dies im Fall sicher ist es die einzige Shared_ptr Beispiel zeigt auf das Objekt (wenn einzigartig () liefert true) und das Objekt benötigt keinen speziellen deleter. Ich würde immer noch Ihr Design in Frage stellen, wenn Sie eine solche .release () Funktion verwendet.

Sie könnten gefälschte deleter verwenden. Dann wird Zeiger nicht tatsächlich gelöscht werden.

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

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

Kinder, dies nicht tun zu Hause:

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

Nun ist es eine Möglichkeit, wenn die Gesamtzahl der Eigentümer zu überprüfen, für den Verweiszähler> 1

Um den Zeiger Punkt nichts lassen wieder, können Sie shared_ptr::reset() nennen.

Allerdings wird dies das Objekt löschen zeigte auf, wenn der Mauszeiger ist die letzte Referenz auf das Objekt. Dies ist jedoch genau das gewünschte Verhalten des Smart-Pointer in dem ersten Platz.

Wenn Sie nur einen Verweis mögen, die nicht das Objekt am Leben halten, können Sie eine boost::weak_ptr (siehe Boost-Dokumentation ). Ein weak_ptr hält an das Objekt einen Verweis aber nicht fügen zu den Referenzzähler, so dass das Objekt gelöscht wird, wenn nur schwache Verweise vorhanden sind.

Die Basis des Teilens ist Vertrauen. Wenn einige Instanz in Ihrem Programm den Rohzeiger lösen muss, ist es fast sicher, dass shared_ptr der falsche Typ ist.

Doch vor kurzem wollte ich dies auch tun, wie ich aus einer anderen Prozess-Heap ausplanen benötigt. Am Ende wurde ich gelehrt, dass meine ältere Entscheidung einige std::shared_ptr zu verwenden war nicht durchdacht.

Ich habe nur routinemäßig diese Art für die Bereinigung. Aber der Zeiger wurde nur an wenigen Orten dupliziert. Eigentlich brauchte ich eine std::unique_ptr, die (Überraschung) eine release Funktion hat.

Vergib ihnen, denn sie wissen nicht, was sie tun. Dieses Beispiel arbeitet mit boost :: shared_ptr und MSVS std :: shared_ptr ohne Speicherlecks!

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

Sie können den freigegebenen Zeiger löschen, die mir viel die gleiche zu sein scheint. Wenn Zeiger immer eindeutig sind, dann ist std::auto_ptr<> eine gute Wahl. Beachten Sie, dass eindeutige Zeiger nicht in STL-Containern verwendet werden, da Operationen auf ihnen eine Menge Kopieren und temporäre Vervielfältigung tun.

Ich bin nicht ganz sicher, ob Ihre Frage zu Erreichung dieses Ziels ist, aber wenn man das Verhalten wollen von einem shared_ptr, wo, wenn Sie den Wert von einem shared_ptr lösen, werden alle anderen gemeinsamen Zeiger auf den gleichen Wert ein nullptr werden, dann können Sie eine unique_ptr in einem shared_ptr setzen, dieses Verhalten zu erreichen.

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

Ausgabe:

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

Dieses Verhalten ermöglicht es Ihnen, eine Ressource (wie ein Array) zu teilen, dann später diese Ressource wieder verwenden, während alle freigegebenen Verweise auf diese Ressource ungültig zu machen.

Hier ist ein Hack Das könnte funktionieren. Ich würde es nicht empfehlen, wenn Sie in einem echten binden sind.

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

Wenn Sie Ihre Zeiger sind in der Tat einzigartig Verwenden std::unique_ptr oder boost::scoped_ptr wenn erstere für Ihren Compiler nicht verfügbar ist. Andernfalls sollten Sie die Verwendung von boost::shared_ptr mit boost::weak_ptr kombinieren. Schauen Sie sich die Boost-Dokumentation .

Ich bin mit Poco :: HTTPRequestHandlerFactory, die ein rohes HTTPRequestHandler * zurück erwartet, löscht das Poco Rahmen der Handler, sobald die Anforderung beendet.

Auch DI Sauce Projekt mit den Controllern zu erstellen, aber der Injektor gibt Shared_ptr, die es nicht direkt zurückgeben kann, und wiederkehr handler.get () ist auch nicht gut, da die, sobald diese Funktion eine shared_ptr geht aus Umfang und Handler löscht dann vor seinem ausgeführt, so ist hier ein vernünftiger (glaube ich) Grund für eine .release () -Methode zu haben. Ich landete eine HTTPRequestHandlerWrapper Klasse erstellen, wie folgt: -

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

und dann die Fabrik würde

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

, die sowohl Sauce und Poco zufrieden und funktioniert gut.

Ich brauchte einen Zeiger durch Asynchron-Handler übergeben und die Selbstzerstörung Verhalten im Fall des Scheiterns zu halten, aber die endgültige API einen Rohzeiger erwartet, so dass ich diese Funktion aus einem einzigen Shared_ptr freizugeben:

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

Wenn ptr.use_count() != 1 Sie müssen stattdessen eine nullptr erhalten.

Einfache Lösung, erhöhen Sie die Referenz und dann leckt die 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()

Dies wird eindeutig ein Speicherleck sowohl verursacht die shared_ptr und die MyType *

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top