以下代码(包含恶意错误)在没有任何警告的情况下编译GCC。但是,当然,它不像开发人员(我)那样有效。
#include <iostream>
struct A
{
bool b;
void set(bool b_) { this->b = b_; }
bool get() const { return this-b; } // The bug is here: '-' instead of '->'
};
int main()
{
A a;
a.set(true);
std::cout << a.get() << std::endl; // Print 1
a.set(false);
std::cout << a.get() << std::endl; // Print 1 too...
return 0;
}
我可以为编译器添加哪个警告(GCC 4.8)以避免这种拼写错误?
链接问题:是否有任何强制(或警告)使用this->
访问成员变量/函数的选项?
答案 0 :(得分:71)
cppcheck
检测到此特定问题:
$ cppcheck --enable=all this-minus-bool.cxx Checking this-minus-bool.cxx... [this-minus-bool.cxx:7]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? (information) Cppcheck cannot find all the include files (use --check-config for details)
没有给出包含路径。如果我添加-I /usr/include/c++/4.8/
,则仍会检测到问题:
Checking this-minus-bool.cxx... [this-minus-bool.cxx]: (information) Too many #ifdef configurations - cppcheck only checks 12 of 45 configurations. Use --force to check all configurations. [this-minus-bool.cxx:7]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? [/usr/include/c++/4.8/bits/ostream.tcc:335]: (style) Struct '__ptr_guard' has a constructor with 1 argument that is not explicit. [/usr/include/c++/4.8/bits/locale_classes.tcc:248]: (error) Deallocating a deallocated pointer: __c
然后cppcheck慢慢完成上述#ifdef
配置。
(作为旁注,local_classes.tcc
中的错误是误报,但这很难说是一个自动化工具,因为它需要知道此处的catch
阻止未设置宏__EXCEPTIONS
时,不应输入网站。)
免责声明:我没有其他cppcheck经验。
答案 1 :(得分:32)
不,this - b
正在指针this
上执行指针算术,尽管b
是bool
类型(b
隐式转换为int
)。
(有趣的是,您可以始终将this + b
设置为b
为bool
类型的指针,因为您可以将指针设置为超过标量的结尾!所以即使你最喜欢的未定义的行为观察者也会允许那个。)
数组边界检查一直是C ++程序员的工作。
另请注意,在您的情况下,使用this
是多余的:因此减少这种过度使用是解决问题的一种方法。
答案 2 :(得分:13)
我想建议另一种工具(除了@ arne-vogel提出的cppcheck
),提供更好的视觉辅助,而不是要求的警告:
使用clang-format自动设置代码格式。结果可能如下所示(取决于设置),通过operator-
周围添加的空格使错误更加明显:
struct A {
bool b;
void set(bool b_) { this->b = b_; }
bool get() const { return this - b; }
};
答案 3 :(得分:-1)
不,没有办法得到警告。隐含的转换虽然有悖常理,但却被语言所允许。
但是,在这个特定的用例中,我们可以做得更好 - 将bool包装在一个包装类中,该类具有显式转换并且没有定义任何算术运算。
这会在逻辑错误时导致编译器错误,如果逻辑正确性是目标,通常会被视为优于警告。
值得注意的是,c ++ 17弃用了bool::operator++
,因为这个算法被认为是邪恶的。
示例:
struct Bool
{
explicit Bool(bool b) : value_(b) {}
explicit operator bool() const { return value_; }
private:
bool value_;
// define only the operators you actually want
friend std::ostream& operator<<(std::ostream& os, const Bool& b) {
return os << b;
}
};
struct X
{
bool foo() {
// compilation failure - no arithemetic operators defined.
// return bool(this-b);
// explicit conversion is fine
return bool(b);
}
Bool b { true }; // explicit initialisation fine
};