2017-08-26 2 views
4

Ich habe einige C-API, die Objekterstellung und -zerstörung behandelt, bietet es: createObject(...) und destroy(...). Ich möchte es in modernere Konstruktions-/Zerstörungsmechanismen integrieren und sie mit intelligenten Zeigern verwenden. Ich fürchte, irgendwann werde ich vergessen, das Objekt zu zerstören, oder eine Ausnahme wird eintreten.Wrapping C erstellen und zerstören Funktionen mit einem intelligenten Zeiger

Ich bin bewusst, benutzerdefinierte Deleter-Funktion für shared_ptr, aber ich kann nicht explizit new aufrufen, weil createOjbect Funktion behandelt Initialisierung.

Kann ich STL Smartpointer in dieser Situation verwenden? Muss ich eine Klasse mit Initialisierung im Konstruktor, Zerstörung im Destruktor und Referenzzählung in dieser Situation von Grund auf neu implementieren?

+1

Warum brauchen Sie Ref Counter in Ihrer Klasse? Rufen Sie einfach createObject im Konstruktor auf, importiere den Destruktor und stellen Sie eine statische Factory-Funktion bereit, die den intelligenten Zeiger auf Ihre Klasse zurückgibt. Der intelligente Zeiger wird mit dem Refcounter-Teil umgehen.Wenn Ihre Klasse endgültig zerstört ist, wird sie automatisch destroy aufrufen. –

+0

Was bewirkt createObject? Was braucht es? Abhängig von Ihrer Antwort kann es Verbesserungen geben. – Yakk

Antwort

6

Die std::shared_ptr ist vollständig in der Lage, ein Objekt mit cutstom Ersteller und Deleter zu erstellen und zu löschen, aber anstelle von new müssen Sie die Creator-Funktion verwenden.

Betrachten wir, wir haben folgendes Konzept und deleter:

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

Um eine Instanz Foo von Funktionen, einfach oben erstellt zu verwalten wie folgt vor:

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

die Verwendung von std::shared_ptr ist ein Overhead, wenn Sie die Eigentumsrechte des Objekts nicht teilen möchten. In diesem Fall ist die std::unique_ptr viel besser, aber für diese Art haben Sie eine benutzerdefinierte deleter Funktors zu definieren, mit denen sie das verwaltete Foo Instanz löschen:

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

/* ... */ 

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

Ich würde hinzufügen, dass Sie oft Cs frei als Deleter-Funktion übergeben können. –

1

C++ 17.

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

Angenommen, Sie eine C-API Einwickeln Bob mit Bob* createBob(some_args...) und destroyBob(Bob*):

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

ein unique_bob kann implizit in eine shared_ptr<Bob> bewegt werden.

ein wenig eine zusätzliche Annahme kann diese Arbeit in 14 ++ C machen:

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

die die Signatur übernimmt dtor void(T*) ist.

In C++ 11 müssen Sie einen neuen statuslosen Funktionszeiger Dispatcher für Null Overhead unqiue ptrs schreiben.

+0

Ich mag Ihre Lösung mit 'std :: integral_constant'. – Akira

0

Posting Komplettlösung für meinen Fall:

Basierend auf @ Akira Vorschläge Ich wickelte es gemeinsame Zeiger verwenden, weil ich dieses Objekt in vielen Palästen geteilt werden soll, und 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; 
}; 
Verwandte Themen