构造函数会影响封闭对象的其他字段,还是静态分析误报?

Can a constructor affect other fields of an enclosing object, or is this a static analysis false positive?

考虑这个 C++ 代码:

struct SomeStruct {
  SomeStruct() noexcept;
};

//SomeStruct::SomeStruct() noexcept {}

class SomeClass {
  const bool b;
  const SomeStruct s;

public:
  SomeClass() : b(true) {}
  operator bool() const { return b; }
};

void f() {
  int *p = new int;
  if (SomeClass())
    delete p;
}

当我 运行 clang --analyze -Xanalyzer -analyzer-output=text 时,我得到 this:

q72007867.cpp:20:1: warning: Potential leak of memory pointed to by 'p' [cplusplus.NewDeleteLeaks]
}
^
q72007867.cpp:17:12: note: Memory is allocated
  int *p = new int;
           ^~~~~~~
q72007867.cpp:18:7: note: Assuming the condition is false
  if (SomeClass())
      ^~~~~~~~~~~
q72007867.cpp:18:3: note: Taking false branch
  if (SomeClass())
  ^
q72007867.cpp:20:1: note: Potential leak of memory pointed to by 'p'
}
^
1 warning generated.

不过,取消注释 SomeStruct 的构造函数的定义会使警告消失。交换 const bool b;const SomeStruct s; 的顺序也会使其消失。在原始程序中,SomeStruct 的构造函数实际上是否有其他一些定义会导致错误分支被带到那里,或者这是 Clang 的静态分析器中的误报?

const 成员在初始化后没有改变的标准兼容方式;任何机制都将成为 UB。

喜欢

struct foo{
  const bool b=true;
  foo(){ b=false; }
};

是非法的,const_casts b 编辑它的代码也是如此:

struct foo{
  const bool b=true;
  foo(){ const_cast<bool&>(b)=false; }
};

(第二个版本编译,但生成 UB)。

遗憾的是,这样的 UB 并不罕见。例如,我可以在 this 指针地址之前用内存实现 SomeStruct 到 fiddle 的构造函数。这将是双重非法的(在构造后修改 const 值,并违反可达性规则),但取决于优化设置它可以工作。

另一方面,编译器可以自由地注意到唯一的构造函数将 true 分配给 b,然后将 operator bool 转换为 return true.

但是,一旦调用可见源代码之外的函数体,静态代码分析器就会放弃证明 b 的状态。放弃这是一件非常合理的事情。在这里,该函数甚至获得了指向同一个临时对象的指针;做一个完整的证明,无论代码是什么,指针都不能改变某些状态 运行 是可能的,但不这样做似乎也是合理的。

风格不错,代码也有点乱。一个可证明的真实分支要么不应该存在,要么失败分支在语义上应该是有意义的。两者都不会发生在这里;任何阅读此代码的人都无法从代码结构中确定正确性;代码结构看起来具有误导性。