计算包含对象的this指针

时间:2013-12-25 14:27:58

标签: c++ inner-classes pointer-arithmetic

以下便携式和符合标准的C ++是否始终返回“成功”?

#include <iostream>
#include <cstddef>

struct Containing {
    struct {
        Containing * get_containing () {
            return reinterpret_cast<Containing *> (
                (char *) this - offsetof (Containing, inner)
            );
        }
    } inner;
};


int main () {
    Containing c;
    std::cout
        << (c.inner.get_containing () == &c ? "success" : "fail")
        << std::endl;
}

1 个答案:

答案 0 :(得分:3)

#include <iostream>
#include <cstddef>

struct Containing {
    struct {
        Containing * get_containing () {
            return reinterpret_cast<Containing *> (
                (char *) this - offsetof (Containing, inner)
            );
        }
    } inner;
};


int main () {
    Containing c;
    std::cout
        << (c.inner.get_containing () == &c ? "success" : "fail")
        << std::endl;
}

您显示的具体代码(我在上面重复过)是正常的,因为支持C兼容性的reinterpret_cast来自POD的第一个元素。

我记得C ++ 11扩展了reinterpret_cast工作的类型集。

但是,只要您引入虚拟功能或其他非POD'y内容,就会超出offsetof的运行状态,以及保证reinterpret_cast的运行状态。


<强> Standardese 即可。通过在我的PDF阅读器中使用“查找”功能,应用于文档[N3290.pdf](C ++ 11的最终草案,与标准相同),在三次鼠标中单击以下有关offsetof的信息提供了:

  

C ++11§18.2/ 4:
  “宏offsetof类型成员 - 指示符)在此国际/地区接受一组受限制的类型参数   标准。如果 type 不是标准布局类(第9条),则结果是未定义的。“

同样,通过点击标题9中关于“类”的标题,然后要求PDF阅读器搜索reinterpret_cast,我发现......

  

C ++ 11 9.2 / 20:
  “指向标准布局结构对象的指针,适当地使用reinterpret_cast转换,指向它   初始成员(或者如果该成员是位字段,则指向它所在的单位),反之亦然“


<强>在实践即可。使用offsetof作为第一个成员是没有意义的,因为它保证在偏移量0(之前没有填充)。为了使这个东西有意义,你必须指代给定代码的一些逻辑推广,其中......

  • 相关成员不是第一个成员。
  • 使用指向字节的指针(例如char)完成指针运算。

然后对于POD类型或C ++ 11更通用的标准布局,offsetof很好,但reinterpret_cast需要特定的编译器支持。使用Visual C ++,没关系。使用g ++,如果可能的话,你可以更好地关闭它的愚蠢警告和相关的愚蠢优化,或绕过void指针。

执行offsetof的限制通常不是一个好主意。例如。对于虚拟继承,偏移量可以变化很大,而不能仅从静态类型信息中推断出来。