1 #pragma once
2 
3 #include <unistd.h> // for close()
4 
5 namespace util
6 {
7 
8 /**
9  * @class FileDescriptor
10  *
11  * This class manages an open file descriptor.
12  *
13  * The file descriptor can be closed by calling close().  Otherwise it will be
14  * closed by the destructor.
15  *
16  * FileDescriptor objects cannot be copied, but they can be moved.  This enables
17  * them to be stored in containers like std::vector.
18  */
19 class FileDescriptor
20 {
21   public:
22     FileDescriptor() = default;
23     FileDescriptor(const FileDescriptor&) = delete;
24     FileDescriptor& operator=(const FileDescriptor&) = delete;
25 
26     /**
27      * Constructor.
28      *
29      * @param[in] fd - File descriptor
30      */
31     explicit FileDescriptor(int fd) : fd(fd) {}
32 
33     /**
34      * Move constructor.
35      *
36      * Transfers ownership of a file descriptor.
37      *
38      * @param other - FileDescriptor object being moved
39      */
40     FileDescriptor(FileDescriptor&& other) : fd(other.fd)
41     {
42         other.fd = -1;
43     }
44 
45     /**
46      * Move assignment operator.
47      *
48      * Closes the file descriptor owned by this object, if any.  Then transfers
49      * ownership of the file descriptor owned by the other object.
50      *
51      * @param other - FileDescriptor object being moved
52      */
53     FileDescriptor& operator=(FileDescriptor&& other)
54     {
55         // Verify not assigning object to itself (a = std::move(a))
56         if (this != &other)
57         {
58             set(other.fd);
59             other.fd = -1;
60         }
61         return *this;
62     }
63 
64     /**
65      * Destructor.
66      *
67      * Closes the file descriptor if necessary.
68      */
69     ~FileDescriptor()
70     {
71         close();
72     }
73 
74     /**
75      * Returns the file descriptor.
76      *
77      * @return File descriptor.  Returns -1 if this object does not contain an
78      *         open file descriptor.
79      */
80     int operator()() const
81     {
82         return fd;
83     }
84 
85     /**
86      * Returns whether this object contains an open file descriptor.
87      *
88      * @return true if object contains an open file descriptor, false otherwise.
89      */
90     operator bool() const
91     {
92         return fd != -1;
93     }
94 
95     /**
96      * Closes the file descriptor.
97      *
98      * Does nothing if the file descriptor was not set or was already closed.
99      *
100      * @return 0 if descriptor was successfully closed.  Returns -1 if an error
101      *         occurred; errno will be set appropriately.
102      */
103     int close()
104     {
105         int rc = 0;
106         if (fd >= 0)
107         {
108             rc = ::close(fd);
109             fd = -1;
110         }
111         return rc;
112     }
113 
114     /**
115      * Sets the file descriptor.
116      *
117      * Closes the previous file descriptor if necessary.
118      *
119      * @param[in] descriptor - File descriptor
120      */
121     void set(int descriptor)
122     {
123         close();
124         fd = descriptor;
125     }
126 
127   private:
128     /**
129      * File descriptor.
130      */
131     int fd = -1;
132 };
133 
134 } // namespace util
135