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).
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.
Related
I would like to treat assignment in an if statement as error:
#include <cstdio>
enum some {
a,
b
};
void foo(some e) {
if (e = a) {
puts("yes");
} else {
puts("no");
}
}
int main() {
foo(a);
return 0;
}
This seems like a sane thing to do, except that I'd like to have something like this too:
boost::optional<int> optionalValue;
if (const auto& value = optionalValue) {
}
-Wall gives me enum.cpp:9: warning: suggest parentheses around assignment used as truth value, but I would like to have something more specific than -Wall
You could declare e to be const. Then assignment would be an error.
Or, you can tell g++ to treat warnings as errors with -Werror. Then, coupled with the appropriate warning setting, any assignment in a if expression will be an error. You can enable only this class of warnings with -Wparentheses However, do note that sometimes it's not a mistake, but done on purpose. Which is why g++ suggests using parentheses to disambiguate from accidental assignment.
If you use a more recent version of g++ then it tells you which warning flag corresponds to which diagnostic. Using g++ 4.9.2 your code gives :
m.cc:9:14: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
This tells you that the error comes from the flag -Wparentheses, which is a subset of -Wall.
You can instruct g++ to treat all warnings as errors by using -Werror. But if you only want to treat this particular warning as an error then you can use:
-Werror=parentheses
This version of g++ does not warn for your suggested code const auto& value = optionalValue, so perhaps it's time to upgrade your compiler version.
I am trying to use constants in a class which should be okay in c++11 but I get this warning:
warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11 [enabled by default]
The problem is that I get this many (more than 10) times for every constant I declare. This effectively fills the build messages and makes any other compiler warnings impossible to find.
I would like to make it so this no longer shows up in my build messages box.
I know people like to see relevant code so here it is:
class GameState: public State
{
public:
const Uint8 * keyStates;
Point gameMousePos;
int UIType;
std::vector<UI *> UIs;
Texture * lockingTex;
HitBox * inGame;
const int buttonDim = 100;
const int buttonOffY = 70;//distance from bottom
const int buttonOffX = 130;//distance from each other
const int buttonTextOffY = 140;//text distance from bottom
bool locking;
bool noPlaceBool;
float gameSpaceScale;
HitBox * gameSpace;
Texture * bkg;
float windowRotSpeed;
float inHandRotSpeed;
float windowMoveSpeed;
GameState();
void handle_events();
void logic();
void render();
void save();
void load_save();
}
The compiler warning tells you exactly what to do:
warning: non-static data member initializers only available with -std=c++11 or -std=gnu++11 [enabled by default]
By default g++ uses C++03.
To activate C++11 features you need to tell the compiler to use C++11
g++ -std=c++11 stuff.cpp
Once you are using C++11 the default features ("enabled by default") for that language will be enabled.
The compiler is telling you that it should be static:
warning: non-static data member ...
So if you were to add the static keyword, it would solve your problem.
So change these:
const int buttonDim = 100;
With:
static const int buttonDim = 100;
And the warnings should go.
Note that was part of C++ for a very long time (only cl [Microsoft compiler] did not support it well before 2008 or so.)
As a side note, a good programmer wants to do the opposite: transform all warnings to errors to be forced to fix all warnings. I very rarely have to go around a warning and it is always rather edgy cases (like compare two floating point numbers with == or !=. So all of that to say, I would actually advice you use -Werror and always find the exact reason for a warning.
Of course, if you are working with someone else code... that's a different story. They may not want to fix their code.
I have a header, core/types.hh, used by several different build targets. It has the following declaration:
core/types.hh
typedef std::size_t Size;
static const Size SZ_MAX = std::numeric_limits<Size>::max();
...
Some of the targets use this constant, some don't. So I get:
error: 'core::SZ_MAX' defined but not used"
I use scons with GCC 4.7.3 on Linux. I have -Wall set and want to keep it that way.
As far as I understand from the GCC documentation, this shouldn't give a warning:
-Wunused-variable
Warn whenever a local variable or non-constant static variable is unused aside from its declaration. This warning is enabled by -Wall.
So I don't see why I get a warning (which turns into an error).
On other answers, people were advised to make the declaration extern and to do the assignment in the file that uses the constant. This file is used by many other files, so it would loose its constant-ness if I do that. Furthermore, this file has header guards, so I think this should mean that the constant is actually created only once.
I'd appreciate any help!
Yuval
Possible duplicates:
How to use typed constants with “unused variable” warnings?
c++ static array declared in h file gives warning 'defined but not used'
It seems that this was not the error that halted compilation.
Rather, if GCC find another error, it would still report on this too.
I actually had another unused variable, and that's what caused this error in the first place.
For example, when creating the following files:
file1.cc
#include "head1.hh"
int main() {
int bad_unused_variable;
return my_ns::JUST_ANOTHER_CONST;
}
head1.hh
#ifndef HEAD1
#define HEAD1
#include <stdint.h>
#include <cstddef>
#include <limits>
namespace my_ns {
typedef std::size_t Size;
static const Size SZ_MAX = std::numeric_limits<Size>::max();
static const Size JUST_ANOTHER_CONST = 8;
}
#endif
You get:
> g++ -Wall -Werror file1.cc -O2 -std=c++98 -o file1
file1.cc: In function 'int main()':
file1.cc:4:6: error: unused variable 'bad_unused_variable' [-Werror=unused-variable]
In file included from file1.cc:1:0:
head1.hh: At global scope:
head1.hh:10:20: error: 'my_ns::SZ_MAX' defined but not used [-Werror=unused-variable]
cc1plus: all warnings being treated as errors
EDIT
This also seems to have been answered here: gcc warnings: defined but not used vs unused variable - there they mention the subtle differences between the two warning messages (unused variable vs defined but not used). Still, it doesn't really answer as to why GCC behaves this way...
g++ generates warnings for unused local variables. Is it possible to have g++ warn for unused class member variables and/or global variables?
class Obj {
public:
Obj(int a, int b) : num1(a), num2(b) {}
int addA(int i) {
return i + num1;
}
private:
int num1;
int num2;
};
How do I get g++ to warn me that num2 is unused?
UPDATE:
I am currently compiling with:
g++ -Wall -Wextra -pedantic *.cc -o myprogram
Clang's -Wunused-private-field enables the warning you're asking for. On your code base, it shows:
$ clang -Wunused-private-field /tmp/nic.cpp
/tmp/nic.cpp:10:22: warning: private field 'num2' is not used [-Wunused-private-field]
int num2;
^
1 warning generated.
I'm not aware of any such warning. Additionally I'll speculate that the reason it doesn't exist is because it can't be reliably generated in all cases, so they elected to not spend effort making it work for some subset of cases. For example, if the class friends another function that's in a library, the compiler would have no way of knowing if that library mutated any particular class attribute or not.
You can use cppcheck (download). cppcheck --enable=style does exactly what you need, among other useful things.
I know it has come up a zillion times but this time it was autogenerated code :
class testGetter{
testGetter * ptr; // wrote this
public:
// this is autogenerated by eclipse
const testGetter*& getPtr() const {
return ptr;
}
void setPtr(const testGetter*& ptr) {
this->ptr = ptr;
}
};
I am on windows 7 mingw - g++ version 4.7.0
So is it a bug in the templates of eclipse (juno) ?
EDIT : compiler invocation :
g++ -O0 -g3 -Wall -c -fmessage-length=0 -fpermissive -o Visitor.o "..\\Visitor.cpp"
EDIT 2013.06.12 : I should have added that I reported the thing after the feedback I got here
const testGetter*&
That represents a reference to a non-const pointer to a const testGetter. You cannot convert from a testGetter* to that type as that would break const-correctness in the following example:
const testGetter tmp;
testGetter t;
t.getPtr() = &tmp; // !!!
If the conversion was allowed the above code would compile, and after the line marked with the !!! the pointer stored inside t (which is of type testGetter*) would be pointing to a const testGetter, breaking const-correctness in the code.
You probably want to return just a pointer, not a reference to a pointer:
const testGetter* getPtr() const
Or alternatively add an extra const to guarantee const-correctness:
const testGetter *const& getPtr() const
In either case, the code is ensuring that you don't set the internal testGetter* to point to a const testGetter.
If the getter was autogenerated by the tool (Eclipse), then the tool has a bug or is a bit too simplistic to generate correct code. You will need to either create the getter manually or else fix the output of the generator.
Sidenote: Given a choice of Eclipse CDT or g++, I'd bet that the bug is in eclipse more often than not.