【发布时间】:2015-05-09 19:36:57
【问题描述】:
这是问题Downcasting using the Static_cast in C++ 和Safety of invalid downcast using static_cast (or reinterpret_cast) for inheritance without added members 的变体
关于 ~B 中的行为,我不清楚标准中的短语“B 实际上是 D 类型对象的子对象,结果指针指向 D 类型的封闭对象”。如果你在 ~B 中转换为 D,那它仍然是一个子对象吗? 下面这个简单的例子说明了这个问题:
void f(B* b);
class B {
public:
B() {}
~B() { f(this); }
};
class D : public B { public: D() {} };
std::set<D*> ds;
void f(B* b) {
D* d = static_cast<D*>(b); // UB or subobject of type D?
ds.erase(d);
}
我知道演员阵容是一扇通向灾难的大门,从 dtor 做这样的事情是个坏主意,但一位同事声称“代码有效且工作正常。演员阵容完全有效。评论明确指出不应取消引用”。
我指出强制转换是不必要的,我们应该更喜欢类型系统提供的保护而不是 cmets。可悲的是,他是高级/首席开发人员之一,并且是所谓的 C++“专家”。
我可以告诉他演员是 UB 吗?
【问题讨论】:
-
我认为这是 UB,但我不确定。然而,代码 [至少在这个示例中] 绝对比我的袜子在炎热的夏天两周没有洗涤后更糟糕......这里的正确做法是在
D中有一个析构函数,从 @ 删除对象987654325@ - 不应该在B中完成。这当然也可以避免 UB 的任何问题。它可能确实有效并且定义明确的事实是无关紧要的。或者将ds变成std::set<B*> bs... -
只要不存在从 B 和 D 派生的任何其他类没有额外的成员,这可能工作正常。但是整个东西都闻起来了。您如何确保每个 B 都是 D,如果可以确定,为什么您首先会有不同的课程?
-
@MatsPetersson:你为什么认为这是 UB? 5.2.9 的标准给出了一个几乎等同于 OP 的示例,尽管它使用了参考:
struct B { }; struct D : public B { }; D d; B &br = d; static_cast<D&>(br);当然,这只是一个理论问题。 OP 问题中的代码太可怕了。 -
@ChristianHackl 关键是 OP 中代码的转换发生在销毁期间,并且确实在
D的析构函数体执行完毕之后。 -
@T.C.:啊,我明白了。你是对的,这让一切变得更加复杂。 OP 那里有很好的高级开发人员... :)
标签: c++ casting language-lawyer static-cast