【发布时间】:2020-01-09 09:38:07
【问题描述】:
考虑以下代码:
struct Base1 { };
struct Base2 { };
struct Foo : Base1, Base2 {
int x;
};
Foo f;
Base1* b1 = &f; // ok, standard upcasting
Base2* b2 = &f; // ok, standard upcasting
// check that the empty base class optimization applies
assert(((void*)b1) == ((void*)&f));
assert(((void*)b2) == ((void*)&f));
assert(((void*)b1) == ((void*)b2));
从 b1 或 b2 访问指向 foo 的指针是否合法?例如
std::cout << reinterpret_cast<Foo*>(b1)->x
<< reinterpret_cast<Foo*>(b2)->x;
如果是,是否同样适用于 C++20 的属性 no_unique_address,假设实现选择将 [[no_unique_address]] 成员视为处理空基类?
例如GCC 和 Clang,但不是 MSVC,目前验证以下内容:
struct Foo {
int x;
[[no_unique_address]] Base1 b1;
char y;
[[no_unique_address]] Base2 b2;
};
static_assert(offsetof(Foo, b1) == 0));
static_assert(offsetof(Foo, b2) == 0));
所以 b1 和 b2 都有其父对象的地址,可以在这里验证:https://gcc.godbolt.org/z/NF9ACy
【问题讨论】:
-
正常的向下转换必须至少使用 static_cast 完成,因为如果没有空基类优化可能会有偏移 - 我特别询问 reinterpret_cast。
-
当然,感谢您的意见 :-)
-
注意我们可能有
offsetof(Foo, b1) == offsetof(Foo, y),没有必要0。 -
并且该属性允许但不强制编译器应用该优化。
-
是的,它是实现定义的,GCC 和 clang 都选择将它们视为空基类(这是本文的建议 - 请参阅此处的 Q.2:open-std.org/JTC1/SC22/WG21/docs/papers/2018/p0840r2.html) .
标签: c++ language-lawyer strict-aliasing c++20