Document number: DxxxxR0
Date: 2017-09-01
Project: ISO JTC1/SC22/WG21, Programming Language C++
Audience: Library Evolution Working Group
Reply to: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>

random_device, no strings attached

1. Introduction and motivation
2. Proposed wording for C++20
    29.6.6 Class random_device [rand.device]
3. References

1. Introduction and motivation

[rand.device] /3 defines the constructor of std::random_device as follows [N4659]. This wording apparently has not been touched since the original proposal in 2002 [N1398].

explicit random_device(const string& token = implementation-defined);

Effects: Constructs a random_device nondeterministic uniform random bit generator object. The semantics and default value of the token parameter are implementation-defined.

(Footnote: The parameter is intended to allow an implementation to differentiate between different sources of randomness.)

On libc++, the default and only supported value of this parameter is the 12-character string "/dev/urandom".

On libstdc++, the supported values include "/dev/urandom", "/dev/random", "default", "mt19937", and anything that looks like an input to strtoul; the default value changes depending on user-controllable preprocessor macros.

Notice that there is no way to construct an object of type std::random_device without first constructing an object of type std::string. This may be problematic for codebases where using the heap is forbidden.

Furthermore, std::random_device's constructor is not allocator-aware; it requires that the input string be constructed using std::allocator. This requires linking in (and template-instantiating) all of the machinery of std::allocator, including operator new, even in programs that just want the default behavior of std::random_device. This machinery will be instantiated, compiled, and linked in, even if the implementation-defined default value is subject to Small String Optimization!

There are many possible overload sets which would adequately address my concern here:

  1. () and (const string&) — my proposed solution
  2. () and (string_view)
  3. (string_view = default)
  4. (const string&) and (string_view = default)
  5. () and (const string&) and (string_view)
The simplest solution, which therefore I propose, is to add a default (zero-argument) constructor and not to add a new dependency on string_view. Solutions 4 and 5 introduce the possibility of overload resolution ambiguity in the case of random_device(X()) where X() is implicitly convertible to either string or string_view.

Any solution involving string_view has the pitfall that a user-provided string_view is not necessarily null-terminated; so if the constructor wants to pass it to fopen (for example), it will have to copy the user-provided bytes into a null-terminated array (perhaps allocated, perhaps of size PATH_MAX/MAX_PATH on the stack). It is better to use the user-provided buffer directly.

2. Proposed wording for C++20

The wording in this section is relative to WG21 draft N4659 [N4659], that is, the current draft of the C++17 standard.

29.6.6 Class random_device [rand.device]

Edit paragraphs 2 and 3 as follows.

class random_device {
public:
  // types
  using result_type = unsigned int;

  // generator characteristics
  static constexpr result_type min() { return numeric_limits<result_type>::min(); }
  static constexpr result_type max() { return numeric_limits<result_type>::max(); }

  // constructors
  random_device();
  explicit random_device(const string& token = implementation-defined);

  // generating functions
  result_type operator()();

  // property functions
  double entropy() const noexcept;

  // no copy functions
  random_device(const random_device& ) = delete;
  void operator=(const random_device& ) = delete;
};

random_device();
explicit random_device(const string& token = implementation-defined);

Effects: Constructs a random_device nondeterministic uniform random bit generator object. The semantics and default value of the token parameter are implementation-defined.

(Footnote: The parameter is intended to allow an implementation to differentiate between different sources of randomness.)

3. References

[N1398]
Jens Maurer. "A Proposal to Add an Extensible Random Number Facility to the Standard Library" (November 2002).
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1398.html
[N4659]
"Working Draft, Standard for Programming Language C++" (March 2017).
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf.