2

I am asking myself the question why

#include <random>
struct A{     
   std::random_device rd; // or any other generator std::mersenne_twister...

   void doStuff() const {
       auto v = rd();
   }

};

const A a;  
a.doStuff(); 

does not work since random_device::operator() is not const.

I thought maybe the random device can still be used when constant but it cannot be seeded again but that is not the case (internal state is obviously not mutable in std::random_device)...

I want to make class A being properly defined (doStuff() is a const method) and now I suddenly need to use mutable std::random_device rd; isn't that ugly?

Is there any reason for this design?

edmz
  • 8,220
  • 2
  • 26
  • 45
Gabriel
  • 8,990
  • 6
  • 57
  • 101
  • 3
    Your title asks a subtly different question that the body text. The title asks why it cannot be const; but it seems you already understand that - the body instead asks why was it not designed to allow const - which is a different question. As such you are likely to get answers that address the title and just tell you what you already know. What you are actually asking however may be a matter of opinion and debate and this not encouraged on SO. – Clifford Jan 31 '16 at 16:32
  • 1
    "or any other generator std::mersenne_twister" Are you asking specifically about `random_device` or about any other generator? – Nicol Bolas Jan 31 '16 at 16:37
  • 4
    This is a perfect example of when to use `mutable`, it isn't ugly. – Brian Rodriguez Jan 31 '16 at 16:38

2 Answers2

8

std::randome_device::operator()() is non-const since it might modify the internal state of the object. std::random_device may be a pseudo random number generator, which uses an internal state for generating numbers. Each time you generate a number you have to modify the internal state, otherwise you would get the same number every single time.

edmz
  • 8,220
  • 2
  • 26
  • 45
Cornstalks
  • 37,137
  • 18
  • 79
  • 144
  • yeah for sure, thats totally fine :-) I am just noting that this makes any use of an PRNG as a member of a class potentially mutable... just because of this... – Gabriel Jan 31 '16 at 16:23
  • That much it seem Gabriel understood. He is not asking why it cannot be const (although the title may suggest that), but rather why is it *designed* that way, when the internal state is an implementation issue and could have been mutable. The answer tot that however may be merely opinion, unless the ISO standard has something specific to say about that. – Clifford Jan 31 '16 at 16:27
8

const can mean many things. It could mean any or all of the following:

  1. Given the same object state and parameters, the same result will happen.

  2. The function will not change the internal state of the object on which it operates.

  3. The function accesses the state of the object in a thread-safe way.

None of these are true for random_device::operator(). You will get different results back; that's the whole point of the function. State that is internal to the object will be affected by requesting it (in one way or another). And the function is most assuredly not thread-safe; calling it on the same object from different threads can cause all manor of badness.

The same is true of any RNG. Getting a random number from an RNG is inherently a non-constant process. That's why the design of C++11 RNGs require the operator() to not be declared const.

As for your goal:

I want to make class A being properly defined (doStuff() is a const method) and now I suddenly need to use mutable std::random_device rd; isn't that ugly?

That depends on what you mean by const. Obviously #2 is out, since you will be changing the mutable state. However, you can still provide #1, for a particular definition of "same result". That is, the "stuff" that doStuff does will be logically consistent. Not binary identical obviously, but within the bounds of the behavior of the function. That's sufficient to be const.

And you can even provide #3, by wrapping your access to your mutable RNG object in a mutex.

Cases like this are exactly why mutable was invented. It's not ugly; you're simply using the feature for what it is designed for. To allow you to access some non-const objects in a way that is logically const to the caller.

Community
  • 1
  • 1
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982