2017-08-14 4 views
2

Je souhaite implémenter une classe en C++ dont le but est de mettre en œuvre un mécanisme RAII pour un objet de type C.Création d'une classe wrapper transparente en C++ pour un objet de style C

Ensuite, je dois être en mesure de passer une instance de cette classe à toutes les fonctions de style C qui reçoivent l'objet de style C mentionné en tant qu'argument. Je sais que cela devrait être résolu avec unique_ptr, mais je ne peux pas utiliser C++11 pour l'instant. Quoi qu'il en soit, j'aimerais comprendre comment cela devrait se faire, même s'il existe de meilleures solutions.

J'ai plusieurs doutes quant aux opérateurs que je dois surcharger, et la différence entre certains d'entre eux. Ci-dessous est un exemple de code avec la mise en œuvre que j'ai faite:

Je suis particulièrement confus avec les opérateurs 1 et 2 (quelle est la différence?)

Je veux savoir si le code que j'ai implémenté couvre tous les cas d'utilisation, je veux dire, tous les scénarios où la bibliothèque C pourrait utiliser le objet. De plus, je voudrais comprendre la différence entre les opérateurs 1 et 2.

objet C-Style

// Example: a C-style library called "clib" which use an object called "cobj": 

struct cobj { 
    int n;  
}; 

void clib_create_cobj(struct cobj **obj) { 
    *obj = (struct cobj*)malloc(sizeof(cobj)); 
    (*obj)->n = 25; 
} 

void clib_release_cobj(struct cobj *obj) { 
    free(obj); 
} 

void clib_doSomething(struct cobj *obj) { 
    std::cout << obj->n << std::endl; 
} 

C++ wrapper "transparent"

// My wrapper class for implementing RAII 

class CobjWrapper { 
    public: 
     CobjWrapper(struct cobj *obj) : m_obj (obj) { } 

     ~CobjWrapper() { 
      if(m_obj != NULL) { 
       clib_release_cobj(m_obj); 
       m_obj = NULL; 
      } 
     } 


     operator struct cobj*() const { // (1) 
      return m_obj; 
     } 

     struct cobj& operator *() {  // (2) 
      return *m_obj; 
     } 

     struct cobj** operator &() {  // (3) 
      return &m_obj; 
     } 

     struct cobj* operator->() {  // (4) 
      return m_obj; 
     } 

    private: 
     struct cobj *m_obj; 

}; 

La principale méthode

// The main method: 

int main() { 
    struct cobj *obj = NULL; 

    clib_create_cobj(&obj); 

    CobjWrapper w(obj); 
    clib_doSomething(w); 

    return 0; 
} 

La source ci-dessus peut être testée ici:

http://cpp.sh/8nue3

+0

Pourriez-vous s'il vous plaît formuler une question claire? Voulez-vous connaître la différence entre (1) et (2)? En ce moment, vous ne demandez vraiment rien mais dites simplement ce que vous ne savez pas. – idmean

+0

Si vous voulez implémenter RAII, vous devez savoir ce que * La règle de trois/cinq/zéro * est. De toute façon, il y a déjà 'std :: unique_ptr' avec un suppresseur personnalisé pour cela. – LogicStuff

+0

FYI: C++ 98 avait 'std :: auto_ptr' à la place de' std :: unique_ptr'. – Zefick

Répondre

3

Ce qui suit est une implicite coulée

operator struct cobj*() const { // (1) 

avec un exemple d'utilisation

CobjWrapper wrapper = /**/; 

struct cobj* obj = wrapper; 

tandis que ce qui suit est la unaire operator *

struct cobj& operator *() {  // (2) 

par exemple l'utilisation

CobjWrapper wrapper = /**/; 

struct cobj& obj = *wrapper; 

BTW, je complètement cacher la struct C, quelque chose comme:

class CobjWrapper { 

    struct ObjDeleter 
    { 
     void operator()(cobj *obj) const { clib_release_cobj(obj); } 
    }; 

    public: 
     CobjWrapper() 
     { 
      cobj *obj = nullptr; 
      clib_create_cobj(&obj); 
      m_obj.reset(obj); 
     } 

     void doSomething() { clib_doSomething(m_obj.get()); } 

    private: 
     std::unique_ptr<cobj, ObjDeleter> m_obj; 
};