2014-03-04 4 views
5

Ich möchte die open/close POSIX-API in ein RAII-kompatibles Objekt wie std::unique_ptr umbrechen. Aber die open Funktion gibt einen int zurück (d. H. Kein HANDLE, der ein Zeiger auf void ist), und ich bin mir nicht sicher, wie ich die Vorlagenklasse std::unique_ptr mit einem int verwenden kann. Kann mir bitte jemand helfen?Wie verwende ich std :: unique_ptr <T> mit einer Schnittstelle, die ein int zurückgibt?

+0

Warum möchten Sie das tun? Wenn Sie keinen Zeiger zum Freigeben haben, ist 'shared_ptr' nutzlos. –

+2

Freigegebener Zeiger ist nicht die richtige Klasse dafür, da der zurückgegebene Wert kein Zeiger ist. Lesen Sie [Vorschlag zum Hinzufügen zusätzlicher RAII-Wrapper zur Standardbibliothek] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3677.html). – RedX

+1

@ FilipeGonçalves Weil es schlau ist und es Ihnen erlaubt, die Datei automatisch zu schließen, wenn niemand sonst Ressourcen streuen muss? – RedX

Antwort

2

Wirklich, alles, was Sie wollen, ist für den Abschluss (int fileHandle) für Sie verwaltet werden, oder? Warum nicht eine einfache C++ - Klasse mit einem Destruktor erstellen, der close() für Sie aufruft? Ich denke, das ist das Verhalten, nach dem Sie suchen.

std :: shared_ptr, und Freunde befassen sich nur mit Heap-Zeigern erstellt mit neuen, und rufen delete ptr, nicht das, was Sie hier suchen.

Edit: Herr Fernandes macht einen guten Punkt. shared_ptr <> verwaltet Verweiszählung für Sie, so ist es eine sehr vernünftige Sache, es mit einem benutzerdefinierten Delet für ein undurchsichtiges Handle von einem c-lib-Aufruf (z. B. Dateihandle) zu tun, wenn nur ein bisschen schwierig für andere Teammitglieder zu folgen. Es beantwortet auch direkt die Frage des OP.

Hier ist ein interesting discussion zum Thema von Herb Sutters Website.

+0

Wenn die Datei nicht geöffnet werden konnte, sollten Sie nicht versuchen, sie im Destruktor zu schließen. – RedX

+0

@Steger Das Problem ist, ich möchte die Klassenobjekte kopieren (-konstruieren). –

+1

@EgorTensin Zum Kopieren können Sie einen lockCount innerhalb des Objekts behalten, indem Sie ihn bei erfolgreichem Öffnen() auf 1 setzen, ihn bei jeder Kopie erhöhen und im dtor dekrementieren. Wenn es auf Null geht, rufe clos() auf. Dies ist der Standard, wie es gemacht wird.Wenn Sie nicht für jede Kopie ein neues Dateihandle öffnen möchten, benötigen Sie keinen lockCount. Ach ja, das Datei-Handle und die Sperr-Anzahl müssten in einem neuen, separaten Objekt sein, so dass es unter mehreren PosixFileHandle-Objekten geteilt werden kann. Ich habe dieses Muster an mehreren Stellen in meinen Programmen. Lass es mich wissen, wenn das nicht klar ist. – Steger

1

Es ist nicht garantiert, nach dem Standard zu arbeiten (das Ergebnis ist implementation-defined), aber ich würde vermuten, dass bei den meisten vernünftigen Implementierungen int -> void* -> int Ihnen den gleichen int Wert geben wird. So könnten Sie dies tun:

std::shared_ptr<void> raii(
    reinterpret_cast<void*>(open(/*...*/), 
    [](void *p) { close(reinterpret_cast<int>(p)); } 
); 

Dieser verwendet eine benutzerdefinierte deleter die close() nennt. Vielleicht möchten Sie dies in Ihre eigene Klasse einbinden, um eine schönere externe Schnittstelle zu präsentieren und trotzdem die std::shared_ptr Implementierung in Bezug auf die Freigabe von & Thread-Sicherheit zu nutzen.

+0

Das Layout von * globalen Zeigern * ist undurchsichtig, kann aber in und von einer Ganzzahl umgewandelt werden. (N1548 §6.3.2.3 ¶5, ¶6) (N3242 §5.2.10 ¶4, ¶5; §3.7.4.3 ¶1, ¶3) Der entsprechende Integer-Typ, von und in den umgewandelt werden soll, wird speziell bereitgestellt, ist aber optional . (N1548 §7.20.1.4) –

+0

Also, '#ifdef INTPTR_MAX' Schalter' int' mit 'intptr_t'. '#ifndef INTPTR_MAX #error" Diese Umgebung ist fehlerhaft. :-("'. –

+1

@CharlesLWilcox Sie müssen 'intptr_t' verwenden, um ein' void * 'auf eine Ganzzahl und zurück zu übertragen. Wenn Sie mit einem' int' beginnen Das Mapping ist einfach implementation-defined (5.2.10p5). – Angew