Status: draft in progress

Overview

This article explains the design of a small RAII wrapper for POSIX file descriptors in C++17.

A file descriptor is only an integer in userspace, but it refers to kernel-managed state. Treating it as a plain integer makes ownership easy to lose track of.

The wrapper is meant to make descriptor ownership explicit and harder to misuse.

Bugs this tries to avoid

The article discusses common descriptor-management bugs:

  • leaking descriptors on error paths
  • closing the same descriptor twice
  • using a descriptor after closing it
  • accidentally leaking descriptors across execve()
  • corrupting unrelated I/O after descriptor reuse

Design notes

The wrapper is move-only.

Copying is disabled because copying an owning descriptor wrapper would make ownership ambiguous. If a second descriptor is needed, duplication should be explicit.

The article walks through:

  • destructor cleanup
  • move construction
  • move assignment
  • valid()
  • get()
  • reset()
  • release()
  • descriptor duplication
  • swap()

close() behavior

One part of the article focuses on close().

On Linux, retrying close() after EINTR can be wrong because the descriptor number may already have been released and reused.

The article checks this against the Linux file descriptor close path in fs/file.c.

Other choices

The draft also explains:

  • why the destructor does not throw
  • why O_CLOEXEC is a good default
  • why construction can return std::optional
  • where this wrapper is useful compared with higher-level C++ I/O abstractions

Current status

The wrapper design exists. The article is being polished together with the public repository and examples.