为什么编译器在声明对象std :: vector但从未使用时不发出警告?

时间:2016-06-20 08:47:51

标签: c++ compiler-warnings unused-variables

#include <vector>

class Object
{
};

int main()
{
    Object myObject;
    std::vector<int> myVector;
}

编译器发出:

warning: unused variable 'myObject' [-Wunused-variable]

myVector没有警告。为什么?有没有办法启用它?

3 个答案:

答案 0 :(得分:21)

一般来说,无论是声明(并因此初始化并在某些时候毁坏)任意对象具有明显的副作用都是无法确定的。构造函数可能正在调用编译器不知道其定义的函数,或者它可能依赖于外部状态或使问题不可判定的任何其他方面。

在第一种情况下,构造函数是微不足道的(甚至没有声明),对于析构函数也是如此。由于Object没有成员,因此Object foo实际上没有任何内容可以清楚且易于检测到。

std::vector有一个非平凡的构造函数,可以分配内存(外部状态+函数,其定义可能不知道(new ...))和非平凡的析构函数(也是外部状态+函数的定义可能未知(delete ...))。在这种情况下,不可能推断出是否可以安全地删除声明(因此发出警告暗示你可能应该这样做),因此编译器必须将声明留在代码中(并且必须假设声明是为了原因)。

一个主要的例子是std::lock_guard,它用于在构造互斥锁时锁定它,并在它被破坏时自动解锁。只要对象在范围内,就可以保持互斥锁;通常你根本不会访问std::lock_guard对象 - 但是声明它是有用的。这是RAII的工作原则。

在这种情况下发出警告会令人讨厌,导致人们关闭警告,这反过来会使警告无效。 (编译器甚至可以设计为只有在优化过程中删除了声明时才会发出警告,这也是为什么只有在启用某些优化时才显示某些警告的原因。)

答案 1 :(得分:6)

此警告仅针对普通类型生成。编译器无法找到构造是否会调用任何外部函数。如果向Object类添加构造函数,则编译器也会发出警告。 Gcc允许标记应生成此警告的类型,您可以使用__attribute__((warn_unused))

执行此操作

http://coliru.stacked-crooked.com/a/0130c8ef29c121a1

示例:

class __attribute__((warn_unused)) Object
{
    public:
    Object(){}
    void use() {}
};

int main()
{
    Object myObject;  // will give : warning: unused variable 'myObject' [-Wunused-variable]
    //myObject.use(); // uncomment to hide this warning
}

[编辑]

来自gcc属性页面:https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html

  

warn_unused 对于具有非平凡构造函数的C ++类型和/或   析构函数,编译器无法确定是否   如果未引用此类型的变量,则该变量确实未使用。这个   type属性通知编译器该类型的变量应该   如果它们似乎未被使用,则被警告,就像变量一样   基本类型。此属性适用于刚才的类型   表示一个值,例如std :: string;它不适合   控制资源的类型,例如std :: lock_guard。

     

这个属性在C中也被接受,但是因为C是不必要的   没有构造函数或析构函数。

答案 2 :(得分:2)

除上述答案外,还请检查编译器文档。可以设置一些编译器,使它们不会多次显示相同的警告。如果您注释掉&#34; myObject&#34;的声明,则可能会对&#34; myVector&#34;发出相同的警告。使用&#34; mObject&#34;首先发出警告,你不会收到警告#34; myVector&#34;。

警告情况下的编译器行为是特定于编译器的,因此不要假设所有编译器都工作相同。 :)