2017-02-22 2 views
0

Ich möchte einfach die Löschfunktion eines shared_ptr ohne den shared_ptr Teil verwenden. Wie in, ich möchte eine Funktion aufrufen, wenn die shared_ptr außerhalb des Geltungsbereichs und der Deleter keinen Zeiger übergeben muss.Wie verwende ich shared_ptr nur für den Deleter?

Ich habe das, aber es ist cheezy.

shared_ptr<int> x(new int, [&](int *me) { delete me; CloseResource(); }); 

Gibt es eine Möglichkeit, keinen Zeiger mit shared_ptr zu verknüpfen?

Update: wie pro viele Vorschläge, die unique_ptr Weise würde wie folgt aussehen:

unique_ptr<int, std::function<void(int*)>> x(new int, [&](int *me) {delete me; CloseResource();}); 

Welche offen schlechter als die Shared_ptr Version sieht, wie viel ‚besser‘, wie es ist.

Update: für diejenigen, die diesen einfachen Umfang wie mit der Funktion Anrufer Schließt Ich habe es ein bisschen einfacher, Sie brauchen nicht einmal zu vergeben oder frei ein Objekt:

shared_ptr<int> x(NULL, [&](int *) { CloseResource(); }); 
+1

'CloseResource' sollte einen Zeiger auf die Ressource akzeptieren, die es schließt – Slava

+4

Warum brauchen Sie einen gemeinsamen Zeiger. Warum nicht nur darauf vertrauen, dass das Objekt seinen Geltungsbereich verlässt? –

+1

Erstens wäre die Verwendung von 'unique_ptr' effizienter (vorausgesetzt, Sie verwenden nicht den Shared-Lifetime-Aspekt von' shared_ptr'). Zweitens, wenn Sie Boost verwenden können, gibt es Boost.ScopeExit, das dies erreicht. Drittens, wenn Sie Boost nicht verwenden können, [können Sie leicht Ihre eigene Klasse erstellen, die dies tut] (http://stackoverflow.com/questions/3669833/c11-scope-exit-guard-a-good-idea) Vermeiden Sie die Hacky-Verwendung von 'unique_ptr' /' shared_ptr'. – Cornstalks

Antwort

3

Es klingt wie das, was Sie kann versuchen, Verantwortung zu tun ist, umdrehen „löschen“ auf „jemand anders“, so dass Sie sich nicht mehr um sie zu kümmern. Wenn das der Fall ist, unique_ptr (nicht shared_ptr) mit einem benutzerdefinierten deleter funktioniert:

struct Foo final {}; 
Foo* New() { return new Foo; } 
void Delete(Foo* p) { delete p; } 

int main() 
{ 
    auto p = New(); 
    std::unique_ptr<Foo, decltype(&Delete)> up(p, &Delete); 
} 

Es gibt eine Reihe von ähnlichen Lösungen here aufgelistet; Es gibt nicht viel mehr, das ohne weitere Informationen über Ihre tatsächliche API getan werden kann (z. B. funktioniert der Trick HANDLE is really a pointer?). Und noch mehr Lesen bei The simplest and neatest c++11 ScopeGuard, einschließlich einer link zu einem vorgeschlagenen std::unique_resource.

0

Wenn Sie eine RAH wie Semantik mit einem Lambda vielleicht etwas wie das wird den Job machen?

namespace details { 
    enum class ScopeExitDummy { }; 
} 


template<typename T> 
class scope_exit_t 
{ 
public: 
    inline scope_exit_t(T&& codeChunk_) 
    : m_codeChunk(std::forward<T>(codeChunk_)) { 
    } 

    inline scope_exit_t(scope_exit_t<T>&& rhs_) 
    : m_codeChunk(std::move(rhs_.m_codeChunk)) 
    { 
    } 

    ~scope_exit_t() { 
    m_codeChunk(); 
    } 

private: 
    T m_codeChunk; 
}; 

template<typename T> 
inline scope_exit_t<T> operator+(details::ScopeExitDummy, T&& functor_) { 
    return scope_exit_t<T>{std::forward<T>(functor_)}; 
} 

#define AtScopeExit auto TW_UNIQUE_VARIABLE(_scopeExit) = details::ScopeExitDummy{} + [&] 

Und Nutzung ist wie:

AtScopeExit { 
    CloseResource(); 
}; 

Hinweis: TW_UNIQUE_VARIABLE ist nur ein Makro, das einen eindeutigen Variablennamen generares so dass der Code mit handschriftlichen Erklärungen kollidieren nicht.

#define TW_STR_CONCAT_IMPL(x, y) x##y 
#define TW_STR_CONCAT(x, y) TW_STR_CONCAT_IMPL(x, y) 

#ifdef __COUNTER__ 
    #define TW_UNIQUE_VARIABLE(prefix) TW_STR_CONCAT(prefix, __COUNTER__) 
#else 
    #define TW_UNIQUE_VARIABLE(prefix) TW_STR_CONCAT(prefix, __LINE__) 
#endif 
+0

Ja, ich könnte eine Template-Klasse erstellen, aber ich habe versucht, das zu vermeiden, da die gesamte Funktionalität, die ich brauche, bereits in shared_ptr existiert. Warum das Rad reproduzieren? – stu

+4

Shared Pointer ist nicht dazu gedacht, einen Deleter bei Zerstörung anzurufen - es ist viel mehr. Es ist nicht neu zu erfinden ein Rad, es zu versuchen, das Rad zu verwenden, um eine Spaghetti zu machen –

+0

Computer sind viel mehr, aber wir verwenden sie nur, um Spiele zu spielen und Tabellenkalkulationen zu machen. Möchte nicht jeder Wiederverwendung? Ich verwende nur einen Teil der vorhandenen Funktionalität, und nicht alles. Ich bin wirklich überrascht, dass es für dieses Problem in der realen Welt keine STL-Lösung gibt, bei der es nicht darum geht, schlechte Dinge wie diese zu tun. – stu

Verwandte Themen