How to create externally unmodifiable variable?

Viewed 205

I'm developing simple simulation library and came across problem, where I have simulation Time variable, which shouldn't be modifiable by API user (programmer) at any circumstances (just provide information about simulation time), but should be modifiable by simulation library, so it cannot be constant.

This is what I came up with yet but it seems a little bit tricky to me

double simTime;                // Internal time, modified by library
const double& Time = simTime;  // Time info provided for programmer in API

Is there an approach for this without const double&?

3 Answers

Instead of const double & you can change your API to provide a function double getTime(); which returns the value of simTime.

I find the const double&-solution rather straight forward and elegant, and I don't see any negative side effects.

The only thing is that your library should declare simTime either as static or in an anonymous namespace such that it cannot be addressed from outside. Otherwise, any extern double simTime in any other translation unit would expose simTime.

So write...

// library.cpp:
static double simTime;
const double &simTimePublic = simTime;

// library.h:
extern const double &simTimePublic;

// userCode.cpp:
#include "library.h"
...
double simTimeCopy = simTimePublic;

// simTimePublic = 1.0; // illegal

You could even (in a public header) define some inline function returning an external variable whose name is long enough to not be easily guessable, e.g.

static inline double getTime(void) {
  extern double somelongname_simTime; // don't use that name directly
  return somelongname_simTime;
}

indeed, the name somelongname_simTime is public, but require malice from the user to be directly used (since it is not declared at file scope in the public header file).

(and you might even use namespace tricks)

Notice that the compiler cannot prevent undefined behavior, such as a pointer getting accidentally the address of a static variable.

And on Linux, you could even play some visibility tricks.


With GCC specifically you might try to have two names to the same global memory location (using assembler labels), e.g. in your public header

extern volatile const double simTime_public asm ("myrealsimTime");

and in some implementation file you'll have instead

double simTime_private asm("myrealsimTime");

Of course you are abusing the compiler and the linker when playing such tricks.

(and obviously you could mix both approaches).

Related