使用offsetof作为模板类

时间:2014-02-05 12:52:13

标签: c++ language-lawyer undefined-behavior offsetof

来自C ++标准:

  

标准布局类是一个类:

     

- 没有非标准布局类型的非静态数据成员(或   这类类型的数组)或参考,

     

- 没有虚函数(10.3),没有虚基类(10.1),

     

- 对所有非静态数据成员具有相同的访问控制(第11条),    - 没有非标准布局基类,

     

- 在派生程度最高的类中没有非静态数据成员   最多一个具有非静态数据成员的基类,或者没有基数   具有非静态数据成员的类,以及

     

- 没有与第一个非静态数据相同类型的基类   构件

     

宏offsetof(type,member-designator)接受一个受限制的集合   本国际标准中的类型参数。如果类型不是   标准布局类(第9条),结果未定义

考虑到这些陈述是否有任何安全的方法可以将offsetof用于依赖模板参数的成员?如果没有,我怎样才能获得模板类中成员的偏移量?使用类似以下内容时可能不安全的事情:

//MS Visual Studio 2013 definition
#define offsetof(s,m)   (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))

非标准布局类?

根据标准,样品不安全的样品:

#include <cstddef>
#include <iostream>

template<typename T>
struct Test
{
    int     a;
    T       b;
};

struct NonStdLayout
{
    virtual void f(){};
};

int main()
{
    std::cout << offsetof(Test<int>, b) << std::endl;
    std::cout << offsetof(Test<NonStdLayout>, b) << std::endl;
    return 0;
}

2 个答案:

答案 0 :(得分:1)

offsetof不能仅用于非标准布局类,因为它们在内存中的布局未知。例如,标准未指定虚拟成员函数的实现方式。一种常见的方法是将指向vtable的指针添加为类的第一个数据成员,但这不是唯一的方法。

关于offsetof的定义:无法保证空指针通过0(或通过C风格的转换)转换为reinterpret_cast,也不保证为其他强制转换为整数的指针值指定的语义。

所以如果你知道你的定义在编译器为你的平台使用的底层寻址方案中有意义,它就可以工作。但是你需要注意的是 if

答案 1 :(得分:1)

答案是在模板中使用offsetof是完全安全的。这样就不会造成伤害。但是,如果您选择这样做,则会对模板的参数类型施加限制。它可以正常用于标准布局类,并且原则上至少编译器应该告诉您何时参数属于不适用的类型。

无论是否涉及任何模板,都无法在标准下获取非标准布局类成员的偏移量。它可能适用于个人编译器,但可能不适用。它可能适用于所有非虚拟类(尽管这不是标准的要求)。也许你只需要进行实验。

我们经常被迫编写不符合标准的代码来解决这类问题,因此我们会仔细测试各个编译器。这只意味着更多的研究和测试工作。