3 ms·
That file class might hold a file descriptor and dup the file descriptor in the copy constructor. If that dup operation fails because you've hit the FD descript
by quotemstr 9y ago
That file class might hold a file descriptor and dup the file descriptor in the copy constructor. If that dup operation fails because you've hit the FD descriptor limit and that copy constructor has no way of indicating that it failed to do its job, you're screwed.
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.
- to3m 9y agoSure, you can do this, but don't. Approximately the last thing you want is a copy constructor that can fail. 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.)
- quotemstr 9y ago> Sure, you can do this, but don't. 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 http://austingroupbugs.net/view.php?id=529
- jandrewrogers 9y agoA common pattern for dealing with failures on construction, such as the example above, without using exceptions is for the object to be constructed in a null state (often useful in any case) and implementing a 'explicit operator bool()' overload that evaluates to false if construction failed or is intentionally null. Of course, that means you have to actually check that construction was successful, similar to returning an error code. It doesn't require you to give up copy constructors etc if they are sensible (and these are usually, but not always, best served by move constructors).
- rramdin 9y agoBut how is requiring the programmer to know that he has to check error codes and whatnot any different from requiring the call be place in a try/catch block? 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.
- erik_seaberg 9y agoYour code isn't really statically typed if every object might support its declared methods, or might instead be an unusable time-bomb. Much better that an invalid object never exists and code that needs that object isn't reachable.