叮当声和海湾合作委员会符合未使用的变量的资格
我在公关评论中注意到一个未使用的变量,我们想知道为什么编译器没有抓住这一点。因此,我用Godbolt进行了以下代码测试,其中有很多未使用的变量,并感到惊讶的是,有些人被报道为未使用,而另一些则没有。即使所有人都没有使用。
#include <string>
struct Index
{
Index(int index) : m_index(index) {}
int m_index;
};
int main()
{
std::string str = "hello"; // case 1. no warning here - unexpected
int someValue = 2; // case 2. warning - as expected
const int someConstant = 2; // case 3. warning - as expected
Index index1(2); // case 4. just as equally not used but no warning - unexpected
// here using the assignment but do get a warning here
// but the str assignment doesn't give a warning - weird
Index index2 = 2; // case 5.
Index index3{2}; // case 6. just as equally not used but no warning - unexpected
Index index4 = {2}; // case 7. just as equally not used but no warning - unexpected
return 0;
}
警告:未使用的变量'someValue'[-wunused-variable]
警告:未使用的变量'index2'[-wunused-variable](仅在clang上警告,而不是在GCC上警告)
警告:未使用的变量'someContant'[-wunused-variable]
,那么clang和GCC符合未使用的条件?如果我使用锁怎么办?我声明了它,但不要直接使用它,而是将其用于自动释放资源。如果有一天开始发出有关锁的警告,我该如何告诉编译器我正在使用它?
int g_i = 0;
std::mutex g_i_mutex; // protects g_i
void safe_increment()
{
const std::lock_guard<std::mutex> lock(g_i_mutex);
++g_i;
// g_i_mutex is automatically released when lock goes out of scope
}
标志: - 变化 叮当:14.0.0 GCC:11.3
I noticed in a PR review an unused variable and we were wondering why compiler didn't catch that. So I tested with godbolt the following code with bunch of unused variables and was surprised that some were reported as unused but others not. Even though all of them are unused.
#include <string>
struct Index
{
Index(int index) : m_index(index) {}
int m_index;
};
int main()
{
std::string str = "hello"; // case 1. no warning here - unexpected
int someValue = 2; // case 2. warning - as expected
const int someConstant = 2; // case 3. warning - as expected
Index index1(2); // case 4. just as equally not used but no warning - unexpected
// here using the assignment but do get a warning here
// but the str assignment doesn't give a warning - weird
Index index2 = 2; // case 5.
Index index3{2}; // case 6. just as equally not used but no warning - unexpected
Index index4 = {2}; // case 7. just as equally not used but no warning - unexpected
return 0;
}
warning: unused variable 'someValue' [-Wunused-variable]
warning: unused variable 'index2' [-Wunused-variable] (warning only on clang, not on gcc)
warning: unused variable 'someConstant' [-Wunused-variable]
So what do clang and gcc qualify as unused? What if I'm using a lock? I declare it but don't use it directly but use it for automatic releasing of a resource. How do I tell the compiler that I am using it if one day it starts to give a warning about the lock?
int g_i = 0;
std::mutex g_i_mutex; // protects g_i
void safe_increment()
{
const std::lock_guard<std::mutex> lock(g_i_mutex);
++g_i;
// g_i_mutex is automatically released when lock goes out of scope
}
flags: -Wunused-variable
clang: 14.0.0
gcc: 11.3
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
没有警告的原因是,当您初始化它们时,非平凡类型类型的变量在技术上并没有使用,而是在功能中切勿访问它们。
考虑一下此示例:
GCC警告
琐事T;
自从此声明以来是未使用的切勿导致任何用户定义的代码运行;唯一的运行是无笨拙的琐碎的构造函数和微不足道的破坏者。因此,根本没有在琐碎的t
上执行任何操作,并且它确实没有使用(它的内存甚至从未触摸)。非平凡的NT;
不会引起警告,但是,实际上它是使用使用运行其构造函数的,即用户定义的代码。这也是为什么编译器不会警告“未使用的锁定后卫”或类似的RAII类的原因 - 它们用于在施工和破坏时运行用户定义的代码,这意味着它们使用了(a)指向对象的指针传递给用户定义的构造函数/destructor = tode =使用=使用)。
这可以通过用
gnu :: pure
属性:在这种情况下,GCC警告他们两个
非平地
是一个no-op,向我们发出了“未使用的变量”警告。 (它还警告gnu :: pure
在void函数上使用,这很公平。您通常不应该这样做。)Clang对以下代码的警告也很有意义。
到以下:
这是等效 具有副作用(称为用户定义的构造函数),因此该临时性并非未使用。但是,然后将临时性移至本地变量
hmm hmm
。移动构造函数和该本地变量的攻击函数都是微不足道的(因此不调用用户代码),因此该变量确实是未使用的,因为编译器可以证明程序的行为是否相同,无论该变量是否相同存在(如上所述,Trivial CTOR + Trivial DTOR +无其他访问变量=未使用的变量)。如果hmm
具有非平凡的移动构造函数或非平凡的破坏者,则不会使用。请注意,一个琐碎的移动构造函数使移动的对象完整保持完整,因此它确实没有任何副作用(除了初始化正在构造的对象之外)。
可以通过删除MOVE构造器来轻松验证,该构建器导致clang and gcc和gcc conflang and gcc compland 。
The reason why there's no warning is that variables of non-trivial class type aren't technically unused when you initialize them but then never access them in your function.
Consider this example:
GCC warns about
Trivial t;
being unused since this declaration never causes any user-defined code to run; the only thing that's run are the trivial constructor and trivial destructor, which are no-ops. So no operation at all is performed onTrivial t
and it is truly unused (its memory is never even touched).NonTrivial nt;
doesn't cause a warning, however, since it is in fact used to run its constructor, which is user-defined code.That's also why compilers are not going to warn about "unused lock guards" or similar RAII classes - they're used to run user-defined code at construction and destruction, which means that they are used (a pointer to the object is passed to the user-defined constructor/destructor = address taken = used).
This can further be proved by marking the object's constructor with the
gnu::pure
attribute:In this case, GCC warns about both of them because it knows that
NonTrivial::NonTrivial()
doesn't have side-effects, which in turn enables the compiler to prove that construction and destruction of aNonTrivial
is a no-op, giving us back our "unused variable" warning. (It also warns aboutgnu::pure
being used on a void function, which is fair enough. You shouldn't usually do that.)Clang's warning about the following code also does make sense.
This is equivalent to the following:
Construction of the temporary
Hmm(2)
has side-effects (it calls the user-defined constructor), so this temporary is not unused. However, the temporary then gets moved into the local variableHmm hmm
. Both the move constructor and the destructor of that local variable are trivial (and therefore don't invoke user code), so the variable is indeed unused since the compiler can prove that the behavior of the program would be the same whether or not that variable is present (trivial ctor + trivial dtor + no other access to the variable = unused variable, as explained above). It wouldn't be unused ifHmm
had a non-trivial move constructor or a non-trivial destructor.Note that a trivial move constructor leaves the moved-from object intact, so it truly does not have any side-effects (other than initializing the object that's being constructed).
This can easily be verified by deleting the move constructor, which causes both Clang and GCC to complain.