boost::checked_delete überladen?
-
typedef void* HANDLE
HANDLE ist void*. Das Problem ist nun aber, dass nich jedes void* ein HANDLE ist und daher nicht mit CloseHandle gelöscht werden soll
Kann man nicht irgendwelche pointer-traits für HANDLE anlegen, mit denen scoped_ptr dann arbeitet?
-
Auf die Weise nicht - typedef's kannst du nicht als Unterscheidungskriterium für Überladungen verwenden. Das heißt für den Compiler sind 'HANDLE' und 'void*' identisch, wenn du nichts dagegen tust (aber das liegt dann vor allem in deiner Disziplin).
-
Ja klar.
Anyway, ich möchte einfach einen scoped_ptr für HANDLE's. Geht das?
-
boostA-G@nGSt@ schrieb:
namespace boost { template<> inline void checked_delete<HANDLE>(const HANDLE& Handle) { if(Handle!=INVALID_HANDLE_VALUE) { CloseHandle(Handle); } } }Fehler: error C2912: explicit specialization; 'void boost::checked_delete<HANDLE>(const HANDLE &)' is not a specialization of a function template
Was ist falsch?
Das geht so in C++ einfach nicht, du darfst Funktions Templates nicht "full" spezialisieren, musst überladen stattdessen (nen nicht-Template Overload hat eh immer Vorrang, daher ist das OK):
namespace boost { inline void checked_delete(HANDLE Handle) { if(Handle!=INVALID_HANDLE_VALUE) { CloseHandle(Handle); } } // eine gültige Spezialisierung sähe z.B. so aus: template <class T> inline void checked_delete(std::vector<T> const& t) { // ... } }Bloss ist das wie schon erwähnt wurde Dreck^4, weil der Overload für sämtliche "void*" gilt, und nicht nur für Handles. Pöse.
Für shared_ptr solltest du lieber beim Anlegen einen geeigneten Deleter übergeben, und scoped_ptr für HANDLE vergiss einfach.
Du kannst natürlich gerne checked_delete überladen wenn dir danach ist Unsinn zu machen, aber du wurdest gewarnt.Wo ist denn überhaupt das Problem? Mach doch einfach nen "handle_guard" der genau für Win32 Handles die mit CloseHandle geschlossen werden sollen bestimmt ist, ist ja kein Aufwand, sind ein paar Zeilen. In Low-Level Code verwende ich das oft so:
struct win32_handle_guard { HANDLE m_h; explicit win32_handle_guard(HANDLE h = 0) : m_h(h) {} ~win32_handle_guard() { if (m_h != 0 && m_h != INVALID_HANDLE_VALUE) { bool rc = ::CloseHandle(m_h); assert(rc); } } };
-
hustbaer schrieb:
Das geht so in C++ einfach nicht, du darfst Funktions Templates nicht "full" spezialisieren
Irrtum. Du kannst sie nicht partiell spezialisieren. Eine vollständige Spezialisierung ist möglich und legal. Allerdings darf eine Spezialisierung die Signatur nicht ändern, aus einem:
template <class T> void f(T* x);kann also kein
template <> void f(int& x);werden, da es keine Ersetzung gibt, die aus T* ein int& macht. Ein
template <> void f(int*);hingegen ist völlig korrekt und eine vollständige Spezialisierung des Base-Templaes.
-
HumeSikkins schrieb:
hustbaer schrieb:
Das geht so in C++ einfach nicht, du darfst Funktions Templates nicht "full" spezialisieren
Irrtum. Du kannst sie nicht partiell spezialisieren....
Puh !!! Da bin ich aber erleichtert - ich war schon schwer verwirrt und eigentlich wage ich nur sehr selten, hustbaer zu widersprechen...

Gruß,Simon2.
-
Hmpf.
Jetzt bin ich zwar verwirrt, aber OK.
Template Funktionen sind von den Regeln her sowieso ... eigen.Was auf jeden Fall geht ist ein non-template-Overload, und ... ich denke man kann auch weitere template-Overloads machen, was dann im Prinzip gleich aussehen kann wie eine partielle Spezialisierung.
-
boostA-G@nGSt@ schrieb:
Ja klar.
Anyway, ich möchte einfach einen scoped_ptr für HANDLE's. Geht das?Ein HANDLE ist kein Pointer. Dann ist es aber Unsinn, dafür scoped_ptr zu verwenden - von den technischen Schwierigkeiten mal ganz abgesehen, die sind nur sekundär. Welchen Sinn haben denn z.B. Operator* und -> im Zusammenhang mit HANDLE? Was sinnvoll sein kann, ist sich an scoped_ptr anzulehnen und ein vergleichbares Ding zu benutzen: scoped_handle meinetwegen. Alles andere ist eine Vergewaltigung des Konzepts von scoped_ptr und mit Sicherheit keine gute Idee. also ungefähr
class scoped_handle : boost::noncopyable { public: explicit scoped_handle(HANDLE h = INVALID_HANDLE_VALUE) : h_( h ) {} ~scoped_ptr() { if ( h_ != INVALID_HANDLE_VALUE ) CloseHandle( h_ ); } void reset(HANDLE h = INVALID_HANDLE_VALUE) { if ( h_ != INVALID_HANDLE_VALUE ) CloseHandle( h_ ); h_ = h; } HANDLE get() const { return h_; } operator HANDLE() const { return get(); } // wenn man mag, muss man abwägen void swap(scoped_handle& other) { using std::swap; swap( h_, other.h_ ); } private: HANDLE h_; }; void swap(scoped_handle& a, scoped_handle& b) { a.swap( b ); }
-
Nur so nebenbei... ihr prüft hier immer nur auf INVALID_HANDLE_VALUE. Euch ist schon klar dass es genügen Funktionen gibt die statt INVALID_HANDLE_VALUE einfach 0 zurückliefern wie z.B. CreateEvent, ja?
-
hustbaer schrieb:
Nur so nebenbei... ihr prüft hier immer nur auf INVALID_HANDLE_VALUE. Euch ist schon klar dass es genügen Funktionen gibt die statt INVALID_HANDLE_VALUE einfach 0 zurückliefern wie z.B. CreateEvent, ja?
Natürlich.

-
hustbaer schrieb:
Nur so nebenbei... ihr prüft hier immer nur auf INVALID_HANDLE_VALUE. Euch ist schon klar dass es genügen Funktionen gibt die statt INVALID_HANDLE_VALUE einfach 0 zurückliefern wie z.B. CreateEvent, ja?
Das mag so sein, ist hier aber irrelevant. Schließlich soll der OP hier nicht alles einfach übernehmen, sondern solche Sachen, die nicht spezifisch etwas mit C++ zu tun haben, selbst ausbügeln. Andernfalls ist das schlicht das falsche Forum.