Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constant correctness and <random>

What is the correct way to deal with (otherwise) constant functions that include a random generator call of C++11's random-class? Should you prefer giving up the constant flag of the function or would it be better to declare generator and distribution as mutable elements of your class? A minimal example (not compiling) might be:

#include <random>

class foo 
{
  std::mt19937 MyGenerator;
  std::normal_distribution<precision_type> gauss;
  double get_rnd() const {return gauss(MyGenerator);}
};
like image 377
user3058865 Avatar asked Sep 26 '14 12:09

user3058865


People also ask

What is a const variable?

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.

What is a const type?

In some programming languages, const is a type qualifier (a keyword applied to a data type) that indicates that the data is read-only.

Why should you use const?

The const keyword allows you to specify whether or not a variable is modifiable. You can use const to prevent modifications to variables and const pointers and const references prevent changing the data pointed to (or referenced).


2 Answers

It really depends on what semantics you give to const member access.

For Standard classes, it is thread-safe to concurrently invoke const members from multiple threads. Leaving members const that mutate an RNG would break that, unless the RNG is fully thread-safe (for non-const use).

You don't have to design your classes the same way, but other developers will probably find it confusing to discover classes that can't be safely "read" (invoke const member functions) concurrently.

One option would be to provide two variations -- a non-const version that uses the internally stored RNG, and a const version that accepts an RNG by non-const reference. (The first can call the second, no const_cast required). This implements the "pay only for what you need" guideline w.r.t thread-safety, as multiple threads can safely use the object if each provides a thread-local RNG instance. It also allows testing using a mock RNG implementation, which is likely even more valuable.

like image 178
Ben Voigt Avatar answered Sep 22 '22 16:09

Ben Voigt


It really depends on what you want to achieve, typical strategies include:

  1. Exposing mutability. Simply do not mark the method as const.

  2. Externalising to expose mutability. Pass the mutable elements (here the generator and distribution) as method parameters, exposing the use of mutability inside, the caller is responsible for any thread-safety implication.

  3. Implementing "logical" constness. If the use of randomness is not considered as breaking the logical constness of the class, you can simply declare the generator and distribution as mutable; beware of thread-safety implications (if necessary, ie in a multi-threaded application, use a mutable mutex)

Which alternative you pick depends on the semantics you which to achieve.

like image 22
Matthieu M. Avatar answered Sep 20 '22 16:09

Matthieu M.