I have a class which holds a number of function pointers and I would like for them all to be initialized to NULL when objects are constructed. To do this I was planning on using memset on the memory locations from the first pointer to that of the last pointer however, I am unsure if this would work 100% of the time.
Is it guaranteed that if these function pointers are declared contiguously within the class that their memory locations would also be contiguous. I assume that padding won't affect what I'm trying to do as any padding bytes would just be set to NULL also.
Example class implementation
class C
{
private:
void (*func1)();
void (*func2)();
void (*func3)();
void (*func4)();
};
It is guaranteed that they appear with increasing addresses in the order declared. This is true in general of data members without intervening access specifiers, so if there are other data members in the class then the only way they could intervene is if there are access specifiers in there.
I don't think it's guaranteed to be safe to modify padding bytes. I don't think it's guaranteed that the implementation won't put "something important" in between data members, although I can't immediately think of anything an implementation would want to put in there. Type information for a strangely-designed accurate-marking GC? Recognizable values to test for buffer overruns?
It's not guaranteed that all-bits-zero represents a null function pointer.
You could deal with the issue of the all-bits-zero representation using something like:
std::fill(&func1, &func4 + 1, (void(*)(void))0);
but that would still leave the issue of padding. You're guaranteed no padding in an array, but not (by the standard) in a class. The ABI used by your implementation might specify struct layout to the degree necessary to ensure that your class above is laid out the same as an array of 4 function pointers.
An alternative is to do the following:
struct function_pointers {
void (*func1)();
void (*func2)();
void (*func3)();
void (*func4)();
};
class C : private function_pointers
{
public:
C() : function_pointers() {}
};
The initializer function_pointers()
dictates that (since it doesn't have a user-declared constructor) the members of function_pointers
are zero-initialized even if the instance of C
itself is only default-initialized. function_pointers
could be a data member rather than a base class, if you prefer to type a bit more to access func1
etc.
Note that C
is now non-POD in C++03. In C++11 C
remains standard-layout after this change, but would not be standard-layout if there were any data members defined in C
, and it is not a trivial class. So if you were relying on POD/standard/trivial-ness then don't do this. Instead leave the definition of C
as it is and use aggregate initialization (C c = {0};
) to zero-initialize instances of C.
Do this first.
class C
{
public:
C() : func1(nullptr), func2(nullptr), func3(nullptr), func4(nullptr)
{ };
private:
void (*func1)();
void (*func2)();
void (*func3)();
void (*func4)();
};
Never ever use memset on non-trivial objects, particularly on those which are polymorphic (having virtual functions or deriving from base class having virtual methods and so forth). If you do it, you would blow-up the vptr which points to vtable! A disaster!
vptr & vtable are used to implement polymorphic behavior, hence respect those hidden class members.
memset should be used when we talk in terms of bits and bytes, not when we talk about objects.
Respect non-trivial objects, say no to memset :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With