禁用本地变量的未初始化警告

3
C++编译器在第一次使用本地变量时可能未初始化发出警告。然而,有时候我知道这个变量在使用前总是会被写入,所以我不需要初始化它。当我这样做时,编译器会发出一个警告。由于我的团队正在使用-Werror编译,代码将无法编译。如何关闭特定本地变量的此警告?以下是我的限制:
  1. 我不允许更改编译器标志。
  2. 解决方案必须适用于所有编译器(即没有gnu扩展或其他编译器特定属性)。
  3. 我只想在特定本地变量上使用此功能。其他未初始化的本地变量仍应触发警告。
  4. 解决方案不应生成任何指令。
  5. 我不能更改本地变量的类。也就是说,我不能简单地添加“什么也不做”的构造函数。
当然,最简单的解决方案是初始化变量。然而,该变量的类型初始化成本较高(甚至默认初始化成本也很高),而且该代码在非常繁忙的循环中使用,因此我不想浪费CPU周期进行初始化,因为它保证会在读取之前被覆盖。
那么,有没有一种平台无关、编译器无关的方法来告诉编译器一个本地变量不需要初始化呢?
以下是可能触发此类警告的示例代码:
void foo(){
    T t;
    for(int i = 0; i < 100; i++){
       if (i == 0) t = ...;
       if (i == 1) doSomethingWith(t);
    }
}

如您所见,第一循环周期初始化了t,第二个循环周期使用了它,因此t永远不会被未初始化的情况下读取。然而,编译器无法推断这一点,因此会发出警告。请注意,为了简洁起见,此代码相当简化。


@gexicide 你可以创建一个带有标志的特殊空构造函数,并将其用于初始化,以避免正常构造函数的昂贵计算:HeavyClass obj(kFlagNone) - Raxvan
4
@gexicide,为什么不在循环外初始化变量t,然后让循环从1而不是0开始? - Frédéric Hamidi
@gexicide 根据你的示例,尝试创建类型为 Data<T> tt,其中 Datatemplate <class T>struct Data { T value; Data(){} };,并使用 t.value 而不是 t。这似乎可以消除 Visual Studio 上的警告。 - Raxvan
2
首先要确保编译器确实存在问题。如果你确定了,那么问题就在于你试图遵循编码规则,而编译器则给出了误报警告而与你作斗争。不要拘泥于规则,可以禁用编译器警告(可能是代码中特定平台)或者忍受性能损失。不要与工具作对,并且不要假设你可以编写漂亮的代码,在任何编译器上都不会发出警告。 - Werner Henze
1
另一个不添加无用初始化器的原因是它可能会抑制检查工具发出的警告。如果代码中存在错误,并且变量在初始化之前被访问,那么单独的工具可以捕获它;如果您添加了虚拟初始化器,则该工具无法知道初始化器提供的值不应使用。 - Keith Thompson
显示剩余12条评论
2个回答

1
我会给出另一种方法:不要禁用警告代码,而是对实现进行一些改进。我看到有两种方法: 第一种方法 你可以使用指针代替真正的对象,并保证它只在需要时进行初始化,例如:
std::unique_ptr<T> t;
for(int i=0; i<100; i++)
{
   if(i == 0) if(t.empty()) t = std::unique_ptr<T>(new T); *t = ...;
   if(i == 1) if(t.empty()) t = std::unique_ptr<T>(new T); doSomethingWith(*t);
}

有趣的是,当i==0时,您可能不需要使用默认构造函数来构造t。我无法猜测您的operator=是如何实现的,但我认为您可能正在分配在您省略的...段中已经分配的对象。


第二个选项

根据你的代码遭受如此大的性能损失,我可以推断出T永远不会是基本类型(int,float等)。因此,您可以重新实现T类,以使用init方法并避免在构造函数中进行初始化。您可以使用一些布尔值来指示类是否需要初始化:

class FooClass()
{
public:
   FooClass() : initialized(false){ ... }

   //Class implementation
void init()
{
   //Do your heavy initialization code here.
   initialized = true;
}

bool initialized() const { return initialized; }

private:
   bool initialized;
}

那么您将能够像这样编写它:

T t;
for(int i=0; i<100; i++)
{
   if(i == 0) if(!t.initialized()) t.init(); t = ...;
   if(i == 1) if(!t.initialized()) t.init(); doSomethingWith(t);
}

好的回答,谢谢。然而,T 的实现超出了我在第三方库中的范围。我无法更改它。 - gexicide
@gexicide,请检查我的编辑答案..是否有意义? - Ian Medeiros

1

如果代码不是很复杂,我通常会展开其中的一个迭代:

void foo(){
  T t;
  t = ...;
  for(int i = 1; i < 100; i++){
    doSomethingWith(t);
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接