3

从 C++ 标准:

标准布局类是这样的类:

— 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,

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

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

— 要么在最派生类中没有非静态数据成员,并且最多有一个具有非静态数据成员的基类,要么没有具有非静态数据成员的基类,并且

— 没有与第一个非静态数据成员相同类型的基类

宏 offsetof(type, member-designator) 在本国际标准中接受一组受限制的类型参数。如果 type 不是标准布局类(第 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;
}
4

2 回答 2

1

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

标准下没有办法获取非标准布局类的成员的偏移量,无论是否涉及任何模板。它可能会在单个编译器中工作,但可能不会。它可能适用于所有非虚拟类(尽管这不是标准的要求)。也许你只需要尝试一下。

我们经常被迫编写不符合标准的代码来解决此类问题,因此我们在各个编译器上仔细测试它。这只是意味着在研究和测试方面更加努力。

于 2014-02-06T13:38:58.473 回答
1

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

至于您的定义offsetof:不能保证空指针转换为0via reinterpret_cast(或通过 C 样式转换),也没有为转换为整数的其他指针值指定任何语义。

因此,如果您知道您的定义在编译器为您的平台使用的底层寻址方案中是有意义的,那么它就可以工作。但这是必须意识到的。

于 2014-02-05T13:00:25.083 回答