被引用对象的动态类型什么时候可以改变? [英] When may the dynamic type of a referred to object change?

查看:23
本文介绍了被引用对象的动态类型什么时候可以改变?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们从一个例子开始:

Let us begin with an example:

#include <cstdio>

struct Base { virtual ~Base() {} virtual void foo() = 0; };
struct P: Base { virtual void foo() override { std::printf("Hello, World!"); } };
struct N: Base { virtual void foo() override {} };

void magic(Base& b);
// Example implementation that changes the dynamic type
// {
//     void* s = dynamic_cast<void*>(&b);
//     b.~B();
//     new (s) N();
// }

int main() {
    std::aligned_storage<sizeof(P), alignof(P)> storage;
    void* s = static_cast<void*>(storage);

    new (s) P();

    Base& b = *static_cast<Base*>(s);

    magic(b);

    b.foo();
 }

根据标准,b.foo() 应该打印什么?

What, according to the Standard, should b.foo() print ?

个人意见:未定义,因为在我们在 magic 中销毁实例后 b 变得陈旧.在这种情况下,将 b.foo() 替换为 static_cast(s)->foo() 会使其合法吗?

Personal opinion: it's undefined because b got stale after we destroyed the instance in magic. In this case, would replacing b.foo() by static_cast<B*>(s)->foo() make it legal ?

所以现在我们有一个可能(或不)合法的例子,对于我们所有的标准主义者来说,更普遍的问题是是否允许改变对象的动态类型.我们已经知道 C++ 编译器可能会重用存储(幸运的是),所以这有点棘手.

So now that we have an example that may (or not) be legal, the more general question at hand for all of us standardistas is whether changing the dynamic type of an object is ever allowed. We already know that the C++ compiler may reuse storage (fortunately), so it's a bit tricky.

这个问题似乎是理论上的,但它对编译器有直接的应用:编译器是否可以将程序中的 b.foo() 去虚拟化为 bP::foo()上面?

The question might seem theoretical, however it has immediate application for compilers: may the compiler devirtualize b.foo() to b.P::foo() in the program above ?

因此我在寻找:

  • 关于我自己的小程序的明确答案(我想不出).
  • 更改对象动态类型的合法方式的一个可能示例(一个就足够了).

推荐答案

根据标准的§8.5.3.2,一个引用在初始化后不能绑定到另一个对象.由于放置 new 创建了一个新对象,因此您违反了该规则,并获得了未定义的行为.

According to §8.5.3.2 of the standard, a reference cannot be bound to another object after initialisation. Since placement new creates a new object, you are violating that rule, and get undefined behaviour.

对象的动态类型不能改变.即使在您的示例中,您也不会更改对象的类型,而是在与旧对象相同的位置创建新的不同对象.如果您考虑一下,更改对象的动态类型将意味着就地调整对象大小以容纳额外的数据成员并更改 VMT(然后会移动其他对象并弄乱指针...) 这在语言规则内是无法完成的.

The dynamic type of an object cannot change. Even in your example, you're not changing the type of an object, but creating a new different object in the same place as the old one. If you think about it, changing the dynamic type of an object would imply resizing the object in-place to accommodate extra data members and changing the VMT (and then that would move other objects and screw up pointers...) which can't be done within the rules of the language.

这篇关于被引用对象的动态类型什么时候可以改变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆