班级成员是否保证在记忆中是连续的?

时间:2013-03-15 11:09:54

标签: c++

我有一个包含许多函数指针的类,我想在构造对象时将它们全部初始化为NULL。为此,我计划在内存位置上使用memset,从第一个指针指向最后一个指针,但是我不确定这是否会在100%的时间内起作用。

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

示例类实现

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

4 个答案:

答案 0 :(得分:10)

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

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

不能保证all-bits-zero表示空函数指针。

您可以使用以下内容处理全位零表示的问题:

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()指示(因为它没有用户声明的构造函数)function_pointers的成员被零初始化,即使C的实例本身只是默认初始化。 function_pointers可以是数据成员而不是基类,如果您更喜欢输入更多内容来访问func1等。

请注意,C现在是C ++ 03中的非POD。在C ++ 11中,C在此更改后仍然是标准布局,但如果在C中定义了任何数据成员,则不会是标准布局,并且它不是一个简单的类。所以,如果你依赖POD /标准/琐碎,那就不要这样做了。而是保留C的定义,并使用聚合初始化(C c = {0};)来初始化C的实例。

答案 1 :(得分:3)

首先这样做。

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

答案 2 :(得分:1)

从不在C ++中执行此操作,除非您确实知道自己在做什么。这非常容易出错,未来的代码维护者(甚至可能是你!)可能无法识别所有存在的陷阱,事情可能会出现严重错误。实现这一目标的C ++方法是编写一个构造函数,正确初始化函数指针nullptr(如果你使用的是C ++ 11)或0

答案 3 :(得分:1)

永远不要在非平凡对象上使用memset,尤其是那些具有多态性(具有虚函数或从具有虚方法等的基类派生)的对象。如果你这样做,你会爆炸指向 vtable vptr !灾难!

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

当我们谈论位和字节时,应该使用

memset,而不是在我们讨论对象时。

尊重非平凡的对象,对memset说不。)