2016-06-19 14 views
2

Ich stolperte auf dieses Problem: Using unique_ptr to control a file descriptor. Die std::unique_ptr ist nicht wirklich für einen allgemeinen Griff geeignet. So ist die allgemeinere KlasseGenerische Griff Klasse

template<class HandleType,HandleType nullvalue,class Deleter> 
class Handle; 

bereits implementiert (vielleicht in Boost), oder sollte ich meine eigenen rollen. Diese Frage wurde zuvor in What wrapper class in C++ should I use for automated resource management? aufgeworfen, aber jetzt haben wir C++ 14, so dass es mehr Alternativen geben kann.

Ich fand auch den folgenden Vorschlag: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3677.html. Also hat auch jemand anderes über dieses Problem nachgedacht.

+2

Eine separate "deleter" Klasse oder Funktion ist unnötig zu kompliziert. Umbrechen Sie einfach den Dateideskriptor in eine Klasse, deren Destruktor den Dateideskriptor schließt. Verwenden Sie dann den gewünschten intelligenten Zeiger: unique_ptr oder shared_ptr. –

+0

@SamVarshavchik: .. oder verwenden Sie überhaupt keine Pttrs, nur Konstruktoren bewegen. – lorro

+1

Ehrlich, ich denke immer noch, dass die Antwort von jalf die beste ist, sogar in der Welt von C++ 14. Jede Implementierung muss verschiedene Funktionen im Konstruktor und Destruktor aufrufen, und der Code ist einfach nicht kompliziert genug, um eine wiederverwendbare Klasse die Mühe wert zu machen. –

Antwort

2

Es gibt keine solche Klasse in C++ Standard noch, so entschied ich mich zu write my own:

template<typename Policy> 
class unique_handle 
{ 
    typename Policy::handle_type h; 

public: 
    unique_handle(const unique_handle&) = delete; 

    typename Policy::handle_type get() const 
    { 
     return h; 
    } 

    typename Policy::handle_type release() 
    { 
     typename Policy::handle_type temp = h; 
     h = Policy::get_null(); 
     return temp; 
    } 

    explicit operator bool() const 
    { 
     return !Policy::is_null(h); 
    } 

    bool operator!() const 
    { 
     return !static_cast<bool>(*this); 
    } 

    void reset(typename Policy::handle_type new_handle) 
    { 
     typename Policy::handle_type old_handle = h; 
     h = new_handle; 
     if(!Policy::is_null(old_handle)) 
     { 
      Policy::close(old_handle); 
     } 
    } 

    void swap(unique_handle& other) 
    { 
     std::swap(this->h, other.h); 
    } 

    void reset() 
    { 
     reset(Policy::get_null()); 
    } 

    ~unique_handle() 
    { 
     reset(); 
    } 

    unique_handle& operator=(unique_handle other) noexcept 
    { 
     this->swap(other); 
     return *this; 
    } 

    unique_handle(unique_handle&& other) noexcept 
    { 
     this->h = other.h; 
     other.h = Policy::get_null(); 
    } 

    unique_handle() 
    { 
     h = Policy::get_null(); 
    } 

    unique_handle(typename Policy::handle_type handle) 
    { 
     h = handle; 
    } 
}; 

Probe Nutzung:

#include <wiertlo/unique_handle.hpp> 
#include <iostream> 
#include <cassert> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

struct file_descriptor_policy 
{ 
    typedef int handle_type; 
    static void close(handle_type handle) 
    { 
     ::close(handle); 
    } 

    static handle_type get_null() 
    { 
     return -1; 
    } 

    static bool is_null(handle_type handle) 
    { 
     return handle == -1; 
    } 
}; 

int main() 
{ 
    typedef wiertlo::unique_handle<file_descriptor_policy> file_descriptor; 
    file_descriptor null_fd; // null file descriptor 
    assert(!null_fd); 
    file_descriptor fd(open("/dev/null", O_WRONLY)); 
    assert(fd); 
    write(fd.get(), "test", 4); 
    file_descriptor other = std::move(fd); 
    assert(!fd); 
    assert(other); 
} 
+0

Ihre 'Politik :: get_null()' ist Genie und löst ein lang bestehendes Problem, das ich gehabt habe. Super und danke. –

+0

Ich mag diesen Ansatz. – user877329