类成员是否保证在内存中是连续的

Are class members guaranteed to be contiguous in memory?

本文关键字:连续 内存 成员 是否      更新时间:2023-10-16

我有一个类,它持有一些函数指针,我希望它们都被初始化为NULL时,对象被构造。为了做到这一点,我计划在从第一个指针到最后一个指针的内存位置上使用memset,但是,我不确定这是否会在100%的时间内工作。

如果在类中连续声明这些函数指针,是否保证它们的内存位置也是连续的?我假设填充不会影响我试图做的事情,因为任何填充字节也会被设置为NULL。

类实现示例

class C
{
private:
    void (*func1)();
    void (*func2)();
    void (*func3)();
    void (*func4)();
};

保证它们按照声明的顺序以递增的地址出现。对于没有插入访问说明符的数据成员来说,这是正确的,因此,如果类中有其他数据成员,那么它们可以进行干预的唯一方式就是在其中有访问说明符。

我不认为修改填充字节是安全的保证。我不认为它保证实现不会在数据成员之间放置"重要的东西",尽管我不能立即想到实现希望在那里放置什么。为设计奇特的精确标记GC输入信息?可识别的值来测试缓冲区溢出?

不能保证全位零表示空函数指针。

您可以使用如下方式处理全位零表示的问题:

std::fill(&func1, &func4 + 1, (void(*)(void))0);

,但这仍然会留下填充的问题。可以保证在数组中没有填充,但在类中没有填充(根据标准)。您的实现所使用的ABI可能指定结构布局到必要的程度,以确保上面的类的布局与包含4个函数指针的数组相同。

另一种方法是:

struct function_pointers {
    void (*func1)();
    void (*func2)();
    void (*func3)();
    void (*func4)();
};
class C : private function_pointers
{
public:
    C() : function_pointers() {}
};

初始化器function_pointers()规定(因为它没有用户声明的构造函数)即使C的实例本身只是默认初始化,function_pointers的成员也是零初始化的。function_pointers可以是一个数据成员,而不是一个基类,如果你喜欢输入更多一点来访问func1等。

请注意,C现在在c++ 03中是非pod。在c++ 11中,C在此更改之后仍然保持标准布局,但如果在C中定义了任何数据成员,则不再是标准布局,并且它不是一个平凡的类。因此,如果你依赖于POD/标准/琐碎,那么不要这样做。相反,保持C的定义不变,并使用聚合初始化(C c = {0};)来零初始化c的实例。

先这么做。

class C
{
public:
    C() : func1(nullptr), func2(nullptr), func3(nullptr), func4(nullptr)
    { };
private:
    void (*func1)();
    void (*func2)();
    void (*func3)();
    void (*func4)();
};

永远不要在不重要的对象上使用memset,特别是那些多态的对象(具有虚函数或派生自具有虚方法的基类等)。如果这样做,就会破坏指向vtablevptr !一场灾难!

vptr ,vtable用于实现多态行为,因此尊重那些隐藏的类成员。

memset应该在使用位和字节时使用,而不是在使用对象时使用。

尊重不平凡的对象,拒绝memset:)

在c++中永远不要这样做,除非你真的知道你在做什么。这是非常容易出错的,并且您的代码的未来维护者(甚至可能是您自己!)可能不会认识到存在的所有陷阱,事情可能会出现可怕的错误。实现这一点的c++方法是编写一个构造函数,正确初始化指向nullptr(如果使用的是c++ 11)或0的函数指针。