关于 [expr.mptr.oper]/4 的问题

发布于 2025-01-15 18:54:23 字数 701 浏览 3 评论 0原文

[expr.mptr.oper]/4指出:

[..] 如果 E1 的动态类型不包含 E2 所属的成员 指的是,行为未定义[..]。

下面的代码是UB吗?

struct B { int a{ 10 };  };
struct D : B { int a{ 15 }; };

B b; 
b.*static_cast<int B::*>(&D::a); // Does [expr.mptr.oper]/4 applies?

从成员访问表达式返回的值只是随机的。为什么?

如果我将上面的代码替换为以下代码,我会得到值 B::a 10

struct B { int a{ 10 };  };
struct D : B { int a{ 15 }; };

D d; 
std::cout << d.*static_cast<int D::*>(&B::a);

为什么现在返回值 10 而不是 15 >?或者为什么问题被解决了(我认为已经解决了)?

[expr.mptr.oper]/4 states that:

[..] If the dynamic type of E1 does not contain the member to which E2
refers, the behavior is undefined [..].

Does the following code is UB?

struct B { int a{ 10 };  };
struct D : B { int a{ 15 }; };

B b; 
b.*static_cast<int B::*>(&D::a); // Does [expr.mptr.oper]/4 applies?

The value returned from the member access expression is just random. why?

If I just replace the above code with the following, I get the value B::a 10:

struct B { int a{ 10 };  };
struct D : B { int a{ 15 }; };

D d; 
std::cout << d.*static_cast<int D::*>(&B::a);

Why now the value 10 returned and not 15? or why the problem is fixed (I think is fixed)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浸婚纱 2025-01-22 18:54:23

成员指针由名称初始化,但此后名称就无关紧要了,重要的是偏移量。给定具有继承的对象的内存布局,派生类数据基类结束之后开始。因此,将派生类成员指针应用到基类中可能会出现越界访问。在您的情况下,派生的 a 成员位于基础之外,因此尝试读取基础对象中的导出::a 偏移量是未定义的行为。

但是将基类强制转换为派生类是安全的(在处理成员指针时),因为派生类继承了与其基类相同的内存布局,甚至更多。所以基指针在派生中“起作用”。

有趣的是,类指针是协变的,但成员指针是逆变的。这意味着成员指针可以安全地向下转型,但不能安全地向上转型——这与类指针完全相反。

Member pointers are initialized by a name, but after that the name is irrelevant, and the offset is what matters. Given the memory layout of the objects with inheritance, the derived class data begins after the base class ends. Thus, applying a derived class member pointer into a base class may access out of bounds. In your case, derived's a member is outside of the base, so trying to read at the derived::a offset in a base object is undefined behavior.

But casting a base to derived is safe (when dealing with member pointers) because the derived class inherits the same memory layout as its base, plus more. So the base pointer "works" in the derived.

It's interesting that class pointers are co-variant, but member pointers are contra-variant. That means the member pointers safe to downcast, but not safe to upcast -- the exact opposite of class pointers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文