通过将前向声明替换为包含来更改代码的含义

Change the meaning of code by replacement of forward declaration with include

本文关键字:代码 包含 替换 声明      更新时间:2023-10-16

Google C++ Style Guide 指出

在极端情况下,将 #include 替换为前向声明可以静默地更改代码的含义。

你能帮我找到一些例子吗?

这里有两种情况。 其中一个是UB,另一个我认为是行为的定义变化(假设没有ODR或类似的违规行为:即,没有调用foo看到A的定义,但我不确定)

namespace N {
struct B {};
struct A;//:B{};
}
void foo(N::B*){
std::cout << "Bn";
}
template<class T, class=std::enable_if_t<!std::is_convertible<T*,N::B*>{}>>
void foo(T*){
std::cout << "Tn";
}
int main() {
foo( (N::A*)0 );
}

struct A;替换为struct A:B{};将更改调用哪个foo重载。

此外,如果调用~A()delete A;可见,delete A;将调用。 否则,如果有一个非平凡的析构函数,我们有 UB。 在这种情况下,代码的含义发生了变化,因为它从UB转到DB,我想这是含义的变化。

我知道的最阴险的例子之一是 C 风格转换与继承相结合。

假设您有:

class Parent1 {};
class Parent2 {};
class Child : public Parent1, public Parent2 {};

然后在其他一些文件中,您从 Parent2 转换为子级:

Parent2* parent2_ptr = new Child;
Child* obj = (Child*)parent2_ptr;

在完整定义下,C型强制转换是一个static_cast,正确地固定了地址。通过前向声明(Child),C风格的演员变成了无声地破坏代码的reinterpret_cast