Vincent Fourmond Vincent Fourmond - 15 days ago 5
C++ Question

Why can a const Class& be initialized to itself?

I was hit by a very stupid but hard to detect bug today. Here is the relevant code:

class Vector;
class PointIterator {
const Vector & x;
const Vector & yv;

PointIterator(const Vector & xv, const Vector & yvo) :
x(xv), yv(yv) { ;};
// ^^ here is wrong
};


Why is such a code legal C++ ? Is there any situation where you could make use of the
yv
variable ? I'm aware of similar questions about
int x = x+1;
, (see this question) but while the latter isn't properly initialized, you still can use the
x
variable, while in the code above, I don't think you can make any use of
yv
.

Bonus point: is there any compilation option that would have made me detect this ? (preferably using gcc, but I also use clang), besides the "unused argument" warning (I have quite a few of those, I know I should clean them up).

Answer

If you compile with g++ -O0 -g main.cpp -Wall -pedantic -Wextra -std=c++14 -o go

main.cpp: In constructor 'PointIterator::PointIterator(const Vector&, const Vector&)':
main.cpp:11:5: warning: 'PointIterator::yv' is initialized with itself     [-Winit-self]
 PointIterator(const Vector & xv, const Vector & yvo) :
 ^~~~~~~~~~~~~
main.cpp:11:53: warning: unused parameter 'yvo' [-Wunused-parameter]
 PointIterator(const Vector & xv, const Vector & yvo) :

As you can see, you get the warning two times. One for the self init and one for the unused parameter. Fine!

The same for clang:clang++ -O0 -g main.cpp -Wall -pedantic -Wextra -std=c++14 -o go

main.cpp:12:19: warning: reference 'yv' is not yet bound to a value when used
      here [-Wuninitialized]
        x(xv), yv(yv) { ;};
                  ^
main.cpp:11:53: warning: unused parameter 'yvo' [-Wunused-parameter]
    PointIterator(const Vector & xv, const Vector & yvo) : 
                                                    ^
main.cpp:8:20: warning: private field 'x' is not used [-Wunused-private-field]
    const Vector & x;

So clang reports also the problem, that the uninitialized ref is used before init. Fine!

What you learn: * use multiple compilers in highest warning level to get all warnings!

That is what we do for all our code, especially in unit tests connected to code coverage.

And you should use a coding guideline which makes it easy to detect such problems by review. Maybe use "m_" for class vars or "_var" for parameters or whatever you prefer. Var names with only a list of letters instead of speaking names is a not so well.

Comments