【问题标题】:Computing the address of an object from the address of one of its member subobject从其成员子对象之一的地址计算对象的地址
【发布时间】:2013-12-22 02:22:29
【问题描述】:

我的情况如下:

//This is Public
class B{/*usefull stuff*/};
B*f();
void g(B*b)();

//Those classes are only declared the translation unit of f and g.
class Whatever1{/*Implementation details only useful to f and g*/};
class Whatever2{/*Implementation details only useful to f and g*/};
class A{
public:
    Whatever1 w1;
    Whatever2 w2;
    B b;
};

在函数g中,我想将参数(指向B的指针)转换为指向A的指针。

B 实例总是包装在 A 实例中。

我最终得到了这个:

ptrdiff_t lag(){
    A a;
    return (char*)&a.b-(char*)&a;}

void g(B*b){
    A*a=(A*)((char*)b-lag());
    //Work with a
}

这个解决方案让我很不舒服。

像这样进行偏移计算是否 100% 正确且可移植?

它会以任何方式触发未定义行为吗?

编辑:std::is_standard_layout::value 为 1。

【问题讨论】:

  • 我不知道它是否会起作用(它对我发出“未定义的行为”),但您可能需要检查offsetof
  • 另外,这个问题有the XY problem的味道。也就是说,您向我们展示了一个解决方案,但没有告诉我们该解决方案试图解决的问题。
  • 如果你必须问某事是否是 UB,它可能是(如果你不必问,那么它可能是无论如何)
  • 是的,offsetof 是要走的路。它恰好在您的原始代码也有效的情况下有效,但是使用 GCC 的 offsetof 实现(可能还有其他一些),如果将它与无效的类型一起使用,您将获得编译时诊断。
  • @CatPlusPlus 我不确定未定义的行为。当他做减法时,他在char*上做;指向对象所在的底层字节数组的指针。如果要将其用于低级代码,尤其是在内存管理系统本身的实现中,这是 C++ 的一个基本特性。 (我确实认为它可能在这里被滥用了。)

标签: c++ c++11 offset language-lawyer undefined-behavior


【解决方案1】:

如果B 始终包含在A 中,那么在A 中添加对B 的父级的反向引用可能会更简洁。如果由于某种原因这不切实际,那么offsetof 将清理它有点,但除此之外,这种方法是有效的,如果有点 c-ish。

void g(B*b){
    A* a = (A*)(((char*)b)-offsetof(class A,b));
    //Work with a
}

【讨论】:

  • 我不想添加反向引用,因为我希望这些对象尽可能小,我缓存了很多。
  • 我们不知道A 是否是标准布局(OP 未能提供此相关信息),因此offsetof(class A, b) 可能会产生 UB。实际上 18.2/4 说“如果类型不是标准布局类(第 9 条),则结果是未定义的”。
  • OP 已被编辑以包含信息std::is_standard_layout< A >::value == 1。因此,我之前的担忧消失了。
  • 我会让这两种方式都明确地转换成reinterpret_cast。并抛出一个关于标准布局的static_assert,另一个在A 的构造函数中,并且可能让BA 私有的类型构造,所以构造B 的唯一方法是A。 UB 可能仍有一些方法可以潜入,但在实践中不太可能发生。
猜你喜欢
  • 2012-07-21
  • 2010-09-12
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 2018-10-19
  • 2023-03-08
  • 1970-01-01
  • 2015-07-01
相关资源
最近更新 更多