向上转型对象的地址

4
假设 BD 的基类(可能是虚拟的,可能是多重继承的,不一定是直接基类)。
obj 成为类型为 D 的对象(不是 D 的子类 - 正好是 D)。

D * d = std::addressof(obj);
B * b = d;

我们能否安全地假设
(char*) d <= (char*) b && (char*) b < (char*) d + sizeof(D)

背景:这是成为一个例程的一步,用于确定某个对象是否已由放置new在特定的aligned_storage中创建。我需要确保如果是,则该对象的所有基对象的指针都指向aligned_storage内的某个地址。


1
问题在于多重继承(例如C同时继承A和B)。看起来你需要使用dynamic_cast而不是直接转换。如果你有没有多重继承的类,你将始终具有相同的地址。 - Pierre Emmanuel Lallemant
4
即使存在多重继承和虚拟继承,进行向上转型时不需要使用dynamic_cast。也就是说,b = d并不一定意味着bd具有相同的物理地址。 - aschepler
1
认为答案是肯定的。我意识到这不是一个证明,而且有点繁琐,但你可以编写一个巨大的测试套件,包含许多BD以及B2D2等各种组合,基本上可以找出答案。 - Lightness Races in Orbit
1
当你说“让obj成为类型为D的对象”时,它是否必须是最派生的对象?它可以是另一个对象的子对象吗?在后一种情况下 - 是的,虚基类的子对象可能位于其派生类对象之外。在菱形继承体系中,它必须位于至少一个分支上(只有一个虚基实例,但是有两个从中派生的子对象 - 他们不能都包含它)。 - Igor Tandetnik
1个回答

0

我非常确定你的假设是安全的,因为D是对象的最终类型。否则,在第一次使用放置new时,这将是危险的。

#include <stdlib.h>
#include <new>

struct B { int i; };
struct D : virtual B { int j; };

int
main()
{
    auto const storage = malloc(sizeof(D));
    D* d = new (storage) D();
    free(storage);
    return 0;
}

如果B位于d之前,则放置新的指针需要根据D的布局进行调整,但是“标准分配函数void* operator new(std::size_t, void*) ...只需返回其第二个参数而不变。”(http://en.cppreference.com/w/cpp/language/new)同样,B的存储不能被放置在超出(char*)d + sizeof(D)的位置,因为这会超出分配的内存。
感谢您分享一个有趣的问题。也许自从提出问题以来,您已经找到了更令人满意的答案。我很想阅读更具体的证明,证明这个假设是否成立。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接