2

tl;dr Is there a posix descriptor value that I can throw into close() and nothing will happen?


Is there a specific value which I could use, like NULL for pointers, for file descriptors? I'd like the code to be uniform, so I thought that I could set the origin descriptor into null descriptor.

class socket
{
    int fd;
public:
    //deleted copy operations
    socket(socket&& other):
                   fd{other.fd}
    {
        other.fd = /*null descriptor*/
    }

    ~socket()
    {
        if (close(fd) == -1)
        {
            throw std::runtime_error{strerror(errno)};
        }
        // ^^ null file descriptor will do nothing on close()
        // like delete nullptr;
    }

I can store a boolean flag, but I'd like to avoid it.

The OS that it will be used on is Ubuntu 16.04, with gcc 5.4. I cannot use any library outside of POSIX and standard library itself, up to version present in gcc 5.4.

I tried to read man pages for open(), close(). They didn't mention any special value to use.

I tried to set it to -1, but I'm not sure if it is safe to use everywhere.

Incomputable
  • 2,188
  • 1
  • 20
  • 40
  • What do you want "the NULL file descriptor" to do? Like `/dev/null`? – user202729 Mar 22 '18 at 14:30
  • @user202729, let me add it to the question. Is it clear now? – Incomputable Mar 22 '18 at 14:30
  • 1
    `NULL`/`0` is the fd for stdin, afair. Take a look at this: https://stackoverflow.com/a/18507245/4181011 – Simon Kraemer Mar 22 '18 at 14:32
  • 1
    @SimonKraemer, I'm not using `NULL` for file descriptors. I tried -1, and it seems to be ok. I'm not sure if it will not explode later. – Incomputable Mar 22 '18 at 14:33
  • Per [this](https://en.wikipedia.org/wiki/File_descriptor) a negative number is the way to go. Not being familiar with it though I'm not posting it as an answer. – NathanOliver Mar 22 '18 at 14:34
  • As the answer linked by @SimonKraemer states, POSIX file calls return non-negative file descriptors and `-1` on error, so you can be sure a negative file descriptor is always invalid, and conversely a valid file descriptor is always non-negative. – jdehesa Mar 22 '18 at 14:35
  • @jdehesa, so should I just delete the question? – Incomputable Mar 22 '18 at 14:35
  • @Incomputable Duplicates are not always bad. – user202729 Mar 22 '18 at 14:46
  • @user202729, closing the same thing twice is bad. I'd like to be able to differentiate erroneous close and intended close. – Incomputable Mar 22 '18 at 14:47
  • @Incomputable Uh... close file descriptor or close questions? – user202729 Mar 22 '18 at 14:47
  • @user202729, Oh, sorry, I didn't get what you mean by your previous comment. I got it now. Yeah, the ones that are more googleable are better. – Incomputable Mar 22 '18 at 14:48
  • @Incomputable I didn't get what you mean by *your* previous comment. Why are you ...... oh, I am saying that duplicate questions on [so] are not always bad. – user202729 Mar 22 '18 at 14:49

1 Answers1

5

A minus 1 value for file descriptor can be used in close call with no detrimental effect on the application other than close returning -1 itself.

Since negative one is guaranteed to never be a valid file descriptor, it will be safe.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • 1
    With this approach, I'll lose ability to differentiate between erroneous close, and intended one, right? – Incomputable Mar 22 '18 at 14:37
  • @Incomputable correct, but are you generally checking return value of a `close` call? You might be a single one developer who does that. – SergeyA Mar 22 '18 at 14:38
  • Well, destructors/move semantics usually handle that for me :) I just thought that during grading some magical thing will happen and bring down the whole program. Thanks for the answer. – Incomputable Mar 22 '18 at 14:39
  • Actually, according to [the docs](http://pubs.opengroup.org/onlinepubs/009696899/functions/close.html) you would have the side effect of having `errno` set to `EBADF`, although I guess you would not be able to tell whether the file descriptor did not exist or it was malformed (i.e. negative). – jdehesa Mar 22 '18 at 14:40
  • 1
    @Incomputable You could check that the file descriptor is not negative before you call `close` so you don't even set any error state as you just don't call `close`. – NathanOliver Mar 22 '18 at 14:42
  • @jdehesa, my program seem to enforce the valid descriptor rule. Basically, during construction it detects if bad descriptor was supplied. It doesn't have any assignment, so cannot mutate. I believe that should make it go from one correct state to the other and not have any holes for bugs to slip through. – Incomputable Mar 22 '18 at 14:43
  • @Incomputable well, this is not what you asked for, though. – SergeyA Mar 22 '18 at 14:45
  • @SergeyA, I've got into typical SO newbie problem: not being able to identify what I exactly want. – Incomputable Mar 22 '18 at 14:46
  • @SergeyA _checking return value of a close call?_ I do it at least after writing (or use `ostream` exception handlers instead). Isn't this the only chance to detect whether just the last flushing of buffers fails (e.g. due to 'volume ful' or 'network connection lost' in case of network drives)? – Scheff's Cat Mar 22 '18 at 15:16
  • @Incomputable you may just be slightly defensive like `if (fd!=-1) if (close(fd)==-1) ...` just to avoid closing your *null descriptor* and get non useful error in return... – Jean-Baptiste Yunès Mar 22 '18 at 17:13
  • @Scheff, yes, this is rationale. But people hardly use it still, and in idiomatic usage it is not even exposed - for example, with file stream people often let destructor of the stream to do the work, in which case all bets are off. – SergeyA Mar 22 '18 at 17:41