Question

Peut boost :: shared_ptr libérer le pointeur stocké sans le supprimer?

Je ne vois aucune fonction de libération existe dans la documentation, également dans la FAQ est expliqué pourquoi il ne fournit pas la fonction de libération, quelque chose comme que la libération ne peut se faire sur les pointeurs qui ne sont pas uniques. Mes pointeurs sont uniques. Comment puis-je libérer mes pointeurs? Ou qui classe Smart Boost pointeur à utiliser qui me permettra la libération du pointeur? J'espère que vous ne direz utiliser auto_ptr:)

Était-ce utile?

La solution

Vous devez utiliser un Deleter que vous pouvez demander de ne pas supprimer le pointeur sous-jacent.

Voir cette réponse (qui a été marqué comme duplicata de cette question) pour plus d'informations.

Autres conseils

Ne pas. L'entrée de la FAQ de Boost:

  

Q . Pourquoi ne pas shared_ptr fournir une fonction release ()?

     

. shared_ptr ne peut pas donner la propriété à moins qu'il est unique () parce que l'autre copie détruira encore l'objet.

     

Considérez:

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.
     

En outre, le pointeur retourné par la libération () serait difficile à désaffecter de manière fiable, comme shared_ptr source aurait pu être créé avec un destructeur personnalisé.

Alors, ce serait en sécurité dans le cas où il est le seul exemple shared_ptr pointant vers votre objet (quand renvoie true uniques ()) et l'objet ne nécessite pas une Deleter spéciale. Je remets en question votre conception encore, si vous avez utilisé une telle fonction .release ().

Vous pouvez utiliser Deleter faux. Ensuite, les pointeurs ne seront pas supprimés réellement.

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

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

Les enfants, ne pas le faire à la maison:

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

Maintenant, est-il un moyen de vérifier si le nombre total de propriétaires pour le compte de référence est> 1

Pour que le point de pointeur pour rien de nouveau, vous pouvez appeler shared_ptr::reset().

Cependant, cela supprimera l'objet pointé lorsque votre pointeur est la dernière référence à l'objet. Ceci, cependant, est exactement le comportement souhaité du pointeur intelligent en premier lieu.

Si vous voulez juste une référence qui ne tient pas l'objet vivant, vous pouvez créer un boost::weak_ptr (voir boost documentation ). Un weak_ptr contient une référence à l'objet, mais ne pas ajouter au compte de référence, de sorte que l'objet est supprimé lorsqu'il existe que des références faibles.

La base du partage est la confiance. Si une instance dans votre programme a besoin de libérer le pointeur brut, il est presque certain que shared_ptr est le mauvais type.

Cependant, récemment, je voulais le faire aussi, comme je l'avais besoin de désaffecter d'un autre tas de processus. A la fin on m'a appris que ma décision plus utiliser certains std::shared_ptr n'a pas été pensé.

Je viens régulièrement utilisé ce type pour le nettoyage. Mais le pointeur était juste dupliqué sur quelques endroits. En fait, je besoin d'un std::unique_ptr, qui (suprise) a une fonction de release.

Pardonnez-leur car ils ne savent pas ce qu'ils font. Cet exemple fonctionne avec boost :: shared_ptr et msvs std :: shared_ptr sans fuites de mémoire!

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

Vous pouvez supprimer le pointeur partagé, ce qui semble bien la même chose pour moi. Si les pointeurs sont toujours uniques, alors std::auto_ptr<> est un bon choix. Gardez à l'esprit que les pointeurs uniques ne peuvent pas être utilisés dans des conteneurs STL, étant donné que les opérations sur les font beaucoup de copie et la duplication temporaire.

Je ne suis pas tout à fait sûr si votre question porte sur la réalisation, mais si vous voulez le comportement d'un shared_ptr, où, si vous relâchez la valeur d'un shared_ptr, tous les autres pointeurs partagés à la même valeur deviennent un nullptr, alors vous pouvez mettre un unique_ptr dans un shared_ptr pour obtenir ce comportement.

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

Sortie:

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

Ce comportement vous permet de partager une ressource (comme un tableau), puis réutiliser plus tard cette ressource tout en invalidant toutes les références partagées à cette ressource.

Voici un hack qui pourrait fonctionner. Je ne le recommanderais pas à moins que vous êtes dans une impasse réelle.

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

Si vos pointeurs sont en effet uniques n'utilisez std::unique_ptr ou boost::scoped_ptr si l'ancien n'est pas disponible pour votre compilateur. Dans le cas contraire envisager de combiner l'utilisation de boost::shared_ptr avec boost::weak_ptr. Consultez le documentation Boost pour plus de détails.

J'utilise Poco :: HTTPRequestHandlerFactory qui compte retourner a * HTTPRequestHandler cru, le cadre Poco supprime le gestionnaire une fois que la demande se termine.

En utilisant aussi projet Sauce DI pour créer les contrôleurs, mais le retourne Injector shared_ptr que je ne peux pas revenir directement, et le retour handler.get () est pas bon non plus depuis le dès que cette fonction retourne le shared_ptr est hors de portée et supprime handler alors avant son exécuté, alors voici une raison raisonnable (je pense) d'avoir une méthode .release (). J'ai fini par créer une classe HTTPRequestHandlerWrapper comme suit: -

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

et l'usine serait

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

qui satisfait à la fois la sauce et Poco et fonctionne bien.

Je avais besoin de passer un pointeur par les gestionnaires et async de garder le comportement d'auto-destruction en cas d'échec, mais l'API final attendu d'un pointeur brut, donc je fait cette fonction pour libérer d'un seul 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;
}

Si tu ptr.use_count() != 1 obtenir un nullptr à la place.

Solution simple, augmenter la référence et la fuite 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()

Cela clairement provoquer une fuite de mémoire à la fois la shared_ptr et MyType *

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top