2017-08-26 4 views
4

J'ai une API C qui gère la création et la destruction d'objets, elle fournit: createObject(...) et destroy(...). Je veux l'intégrer dans des mécanismes de construction/destruction plus modernes et les utiliser avec des pointeurs intelligents. J'ai peur qu'à un certain moment j'oublie de détruire l'objet, ou une exception se produira.Habillage C créer et détruire des fonctions à l'aide d'un pointeur intelligent

Je suis conscient de la fonction de suppression personnalisée pour shared_ptr, mais je ne peux pas appeler explicitement new, car la fonction createOjbect gère l'initialisation. Puis-je utiliser des pointeurs intelligents STL dans cette situation? Dois-je, à partir de zéro, implémenter une classe avec l'initialisation dans le constructeur, la destruction dans le destructeur et le comptage des références dans cette situation?

+1

Pourquoi avez-vous besoin ref counter dans votre classe? Appelez simplement createObject dans le constructeur, destroy dans destructor et fournissez une fonction d'usine statique qui retournera un pointeur intelligent vers votre classe. Pointeur intelligent gérera la partie refcounter.Quand votre classe est finalement détruite - elle appellera automatiquement destroy –

+0

Que retourne createObject? Qu'est-ce que ça prend? Selon votre réponse, il peut y avoir des améliorations. – Yakk

Répondre

6

Le std::shared_ptr est entièrement capable de créer et de supprimer un objet avec un créateur de cutstom et un suppresseur, mais au lieu de new vous devez utiliser la fonction de créateur.

Considérons, nous avons le créateur et Deleter suivants:

typedef struct { 
    int m_int; 
    double m_double; 
} Foo; 

Foo* createObject(int i_val, double d_val) { 
    Foo* output = (Foo*)malloc(sizeof(Foo)); 

    output->m_int = i_val; 
    output->m_double = d_val; 

    puts("Foo created."); 
    return output; 
} 

void destroy(Foo* obj) { 
    free(obj); 
    puts("Foo destroyed.");   
} 

Pour gérer une instance de Foo créé par les fonctions ci-dessus, il suffit de faire ce qui suit:

std::shared_ptr<Foo> foo(createObject(32, 3.14), destroy); 

Utilisation de la std::shared_ptr est une surcharge si vous ne souhaitez pas partager la propriété de l'objet. Dans ce cas, le std::unique_ptr est beaucoup mieux, mais pour ce type, vous devez définir un foncteur Deleter personnalisé avec laquelle il peut supprimer la gestion Foo exemple:

struct FooDeleter { 
    void operator()(Foo* p) const { 
     destroy(p); 
    } 
}; 
using FooWrapper = std::unique_ptr<Foo, FooDeleter>; 

/* ... */ 

FooWrapper foo(createObject(32, 3.14)); 
+1

J'ajouterais que vous pouvez souvent simplement laisser C libre comme fonction de suppression. –

1

17 C++.

template<auto X> using constant_t=std::integral_constant<std::decay_t<decltype(X)>, X> 
template<auto X> constexpr constant_t<X> constant{}; 
template<class T, auto dtor> using smart_unique_ptr=std::unique_ptr< T, constant_t<dtor> >; 

Supposons maintenant que vous avez une API C enveloppant Bob avec Bob* createBob(some_args...) et destroyBob(Bob*):

using unique_bob=smart_unique_ptr< Bob, destroyBob >; 
unique_bob make_unique_bob(some_args args){ 
    return unique_bob(createBob(args)); 
} 

un unique_bob peut être implicitement déplacé dans un shared_ptr<Bob>.

Un peu d'une hypothèse supplémentaire peut faire fonctionner en C de 14:

template<class T, void(*dtor)(T*)> using smart_unique_ptr=std::unique_ptr< T, std::integral_constant<decltype(dtor),dtor> >; 

qui assume la signature de dtor est void(T*).

Dans C++ 11, vous devez écrire un nouveau répartiteur de pointeur de fonction sans état pour zéro ptrs unqiue supplémentaires.

+0

J'aime votre solution avec 'std :: integral_constant'. – Akira

0

affichage solution complète pour mon cas:

Basé sur @ suggestions d'Akira J'enroulai à l'aide de pointeur partagé, parce que je veux cet objet partagé dans de nombreux palais et lambda:

// coming from some API: 
struct SomeStruct; 
bool initializedata(SomeStruct **data); 
bool destorycdata(SomeStruct **data); 

class SomeStructWrapper 
{ 
public: 
    SomeStructWrapper() 
    { 
     SomeStruct* data; 
     if(initializedata(&data)) 
     { 
      m_data = std::shared_ptr<SomeStruct>(data, [](SomeStruct* ptr){ 
       destorycdata(&ptr); 
      }); 
     } 
     else 
     { 
      throw std::runtime_error("Data was not initalized"); 
     } 
    } 

    const SomeStruct* operator->() const {return m_data.get();} 
    SomeStruct* operator->() {return m_data.get();} 

private: 
    std::shared_ptr<SomeStruct> m_data; 
};