Sure, you can give up on copy constructors altogether and manually manage resource copies, but doing so impoverishes the language, wrecks one of its best features, and makes programs both more verbose and probably a bit slower.
Sure, you can give up on copy constructors altogether and manually manage resource copies, but doing so impoverishes the language, wrecks one of its best features, and makes programs both more verbose and probably a bit slower.
If you have to do an OS call to duplicate the underlying resource, assume the class isn't copyable in this way. It's almost certainly possible to make it moveable, and this will get you the bulk of the benefit: you can return it from functions, and you have a std::vector of it.
(Also worth noting that close (2), which presumably you'd call from the destructor, can fail with EIO or EINTR. I don't consider looping on EINTR ever safe, but that's up to you. EIO, on the other hand - what are you going to do about that? And if you don't call close from the destructor, what the hell use is this class anyway?? Overall, I don't think value objects make very good wrappers for a POSIX-style file descriptor.)
It was instructive. That said, there's nothing wrong in general with a class that owns a file descriptor, and making this class copy constructible as a legitimate design decision.
> Also worth noting that close (2), which presumably you'd call from the destructor, can fail with EIO or EINTR.
IO errors from close(2) should be ignored. If you care about durability, call fsync before you close. Even if close "fails" with an IO error, the underlying FD is still closed. EINTR does not actually happen.
See extensive discussion http://austingroupbugs.net/view.php?id=529
Most cases where exceptions are useful are when the alternative is knowingly causing such a state that will inevitably lead to a seg fault. It's much easier to raise at the point of failure instead of trying to limp until the application eventually crashes or loses you all your money.