yau yau - 2 months ago 37
C++ Question

No warning, when passing a member variable by (const) reference to a non-const member function

I just ran into an error that rises the question:


  • Shouldn't I get a compiler warning (MSVC2013) for that, or

  • should I learn a new guideline to follow, or

  • am I doing something completely stupid?



I'm within a member function and pass a member variable by
const&
-parameter to another member function. The called function is non-
const
.
If I think about that, I'm pretty sure I just shouldn't do that.

The danger is that the
const&
parameters could get magically changed within the called function, when by chance it modifies the originally passed-in member variable. It is allowed to, not being declared
const
.

The example in code:

struct S
{
void caller()
{
called_one(this->memvar);
}

void called_one(const int& x)
{
// ...
this->memvar = 2; // changes x! That's surprising... at least for this function
// ...
}

private:
int memvar{};
}


I think it would be nice to not accidentally run into that error again.
Perhaps it is not the easiest task for the language or compiler to guard against that?
I didn't came across that issue in some popular source of guidelines either yet.

UPDATE:

Perhaps I should clarify, that I don't find the behavior strange. I don't wonder why aliased variables get changed or anything.
It would be nice, if the answers just focused on what function
called_one
finds strange, not myself ;)

UPDATE:

... and
caller
is the one, doing something wrong.
But I think he has a fair chance to realize that (by reading the code). He is passing an alias to something he knows the called function could modify also (not via the parameters passed). And this could lead to unexpected behavior within the called function.

So, if even in this special case it is not possible or reasonable for the compiler to help, I don't see why introducing that pitfall in the form of a guideline isn't worthy or useful.

Answer

Your question is equivalent to define

f(int& x, const int& y) { x = 2; }

and then to call

f(x, x);

which modifies the second argument x without any warning. You just have created an alias between both arguments. So if your call modifies the first argument, it also modifies the second argument.

The compiler has no way to know all alias information between variables. Its job is just to provide a correct code for all possible aliases. As the call respects the signature, the compiler should not deliver any warning.

UPDATE:

There are no guideline at the language level to prevent such undefined behavior. Aliases are likely to take many forms. For example, a function can modify a data structure (tree, list, vector) from its root at the initiative of one of its element. Then from the root, you can reach the element and accidentaly modify the element or worse its support. As you said, it is the programmer's responsibility to take care about these points.

The compiler could look at the arguments and detect if two arguments are in (trivial) alias with the same type and different const information. But sometimes the programmers want such a behavior without any warning; ex:

void mul_assign(double& x, const double& y) { x *= y; }
void sqr_assign(double& x) { mul_assign(x, x); }