0

Is it possible to make a const& truely immutable?

int* side_effect;
void function(int const& i){
  *side_effect = 123;
}

int main(){

  int i = 0;
  side_effect = &i;

  //based on the function signature, i is suspected not to change.  
  //however, that is not the case.
  function(i);
}

Are there any compiler warnings, attributes, compiler extensions, or language features I can employ to avoid these kinds of problems?

Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271
  • Didn't we have this question just recently? [Here](http://stackoverflow.com/q/34509616). – Kerrek SB Jan 07 '16 at 03:21
  • 3
    `const &` does not mean "can't be changed". It means "can't be changed **through this argument**". – Pete Becker Jan 07 '16 at 03:47
  • 1
    Create a local copy instead of a reference to something else! – Yakk - Adam Nevraumont Jan 07 '16 at 03:59
  • (M)any feature(s) can be broken deliberately. Having a global pointer should not be used the way it is used in your example. However you may try to put a check such as `if(side_effect != &i)` before assigning. – iammilind Jan 07 '16 at 04:29
  • Declare `const int i = 0;` and the compiler will certainly warn you when you assign it's address to a non-const pointer. Any other possible interpretation of your question leads to extensive and somewhat pointless (though pointered) run-time checks. – rici Jan 07 '16 at 05:07

1 Answers1

0

If you want a value to be a true constant, you can pass it as a template value argument.

template<int i>
void function(){
  *side_effect = 123;
}

there is no way for any operation to modify i.

This requires that the input be a compile-time constant (and verified so by the compiler at compile time).

So this doesn't work:

int main(){
  int i = 0;
  side_effect = &i;

  function<i>();
}

as i is not a compile-time constant. If we instead made it:

int main(){
  const int i = 0;
  side_effect = &i;

  function<i>();
}

the function<i> line works, but the side_effect = &i doesn't work. If we add in a cast:

int main(){
  const int i = 0;
  side_effect = const_cast<int*>(&i);

  function<i>();
}

now the operation *side_effect = 123 becomes UB within function.

Another approach which doesn't require that the value being passed in is a true compile-time constant is to not take a reference:

void function(int i){
  *side_effect = 123;
}

and instead take a local copy (either int or const int as the argument, depending on if we want function to have the rights to modify i).

The full strength version of what you want -- that we take a reference to external data, and then ensure that the external data remains unchanged -- can pretty easily be shown to be equivalent to the halting problem in the general case.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524