web-dev-qa-db-fra.com

Utilisation de std :: make_unique avec un suppresseur personnalisé

À l'aide de std::unique_ptr avec un suppresseur personnalisé que je souhaite utiliser std::make_unique plutôt qu'un nouveau brut. J'utilise VC++ 2013. Il me semble qu'il n'y a aucun moyen d'utiliser std::unique_ptr si vous utilisez un suppresseur personnalisé. Ai-je raté quelque chose ou est-ce vraiment le cas?


Information additionnelle:

J'utilise un std::unique_ptr<HANDLE, custom_deleter> pour contenir un HANDLE Windows pour un port COM ouvert.

Je pourrais écrire une classe RAII personnalisée pour cela, et ce ne serait pas terriblement difficile, mais je voyais à quel point ce serait difficile/difficile/mauvais d'utiliser std::unique_ptr.

32
Graznarak

Tout l'intérêt de make_unique consiste à encapsuler la notion d '"utiliser new pour créer un T à partir d'arguments constructeurs donnés et utiliser delete pour le détruire ".

Si vous vouliez un suppresseur personnalisé, vous devrez également spécifier comment créer l'objet, et alors il n'y aurait rien de plus à gagner avec le fabricant de placement fonction.

J'ai écrit quelques exemples de fonctions de création personnalisées pour certains descripteurs de ressources uniques dans cet article .

25
Kerrek SB

Voici un moyen d'encapsuler la gestion de la mémoire de style c dans un std::unique_ptr en utilisant un suppresseur personnalisé qui appelle une fonction libre personnalisée. Cela a une aide de fonction make similaire à std::make_unique LIVE :

#include <iostream>
#include <functional>
#include <memory>

// Some C style code that has some custom free function ptr...
extern "C" {

struct ABC { };

enum free_type_e {
    FREE_ALL,
    FREE_SOME
};

typedef void (free_f)(enum free_type_e free_type, void *ptr);
struct some_c_ops { free_f* free_op; };

void MY_free(enum free_type_e free_type, void *ptr)
{
    printf("%s:%d ptr=%ld\n", __func__, __LINE__, (long)ptr);
    (void)free_type;
    free(ptr);
}

}; // extern "C"

template<typename T>
using c_unique_ptr = std::unique_ptr<T,std::function<void(T*)>>;

template <typename T>
c_unique_ptr<T> make_c_unique(some_c_ops* op, free_type_e free_type)
{
    return c_unique_ptr<T>(static_cast<T*>(calloc(1, sizeof(T))),
                           std::bind(op->free_op, free_type, std::placeholders::_1));
}

void foo(c_unique_ptr<ABC> ptr)
{
    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) <<     std::endl;
}

int main()
{
    some_c_ops ops = { MY_free };
    c_unique_ptr<ABC> ptr = make_c_unique<ABC>(&ops, FREE_ALL);
    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) << std::endl;

    foo(std::move(ptr));

    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) << std::endl;
}

Sortie possible:

main:48 ptr=50511440
foo:40 ptr=50511440
MY_free:20 ptr=50511440
main:53 ptr=0
0
Jon Ringle