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



考虑下面的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时,我得到这个:

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_castb编辑的代码一样:

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

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

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

另一方面,编译器可以自由地注意到唯一的构造函数将true赋值给b,然后将operator bool转换为只返回true

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

样式方面,代码也有点乱。一个可证明为真的分支不应该存在,或者失败分支应该在语义上有意义。这两种情况在这里都没有发生;任何阅读这段代码的人都不能从代码结构中判断正确性;代码结构看起来很容易误导。

最新更新