class A
{
public:
A()
{
}
virtualvoid Draw()
{
int z = 0;
}
};
class B : public A
{
public:
void Draw()
{
int x = 0;
}
};
class C
{
public:
B b;
C()
{
memset(this, 0, sizeof(C));
}
};
//-----------------------------------------------------------------------------
void main()
{
C c;
A *pA = &c.b;
pA->Draw(); // <------ 0xC0000005: Access violation reading location 0x00000000.
}
I understand that it comes from memset in class C, but why???
You must never ever use memset or any other dumb memory operation (like memcpy, memcmp, binary file i/o, etc) on a complex type. This is just one of many reasons why.
Since A is polymorphic (has at least 1 virtual function), it has a hidden 'vtable' bundled into it. Among possibly other things, this vtable contains function pointers for all the virtual functions in the class, so it knows what type the object is, as well as what functions to call when a virtual function call occurs.
When you memset the object, you are wiping out the vtable, destroying all that information. Hence the access violation.
I do memset in constructor as I have a lot of members: pointers and arrays in the class C that I need to set to NULL on initialization. Can you recommend something how to zero out at once all members but do not affect vtable?
With a current code structure, the only solution I could came up with is to declare "b" as a pointer.
Can you recommend something how to zero out at once all members but do not affect vtable?
Assign all of them to 0 in constructor initializer list.
Alternatively you can store all primitive implementation data in member POD struct and zero it out:
If you have C++11 support.... I believe this is now legal:
1 2 3 4 5 6 7 8 9
class A
{
private:
int a = 0;
int b = 0;
int c = 0;
// no need to write default constructor
};
But I can't remember whether or not that's correct. Try it and see.
If you are using raw pointers (you said you need to initialize to null) -- you're probably doing it wrong. Raw pointers don't have much use in C++... consider using smart pointers instead (which will default initialize themselves with null so you don't have to)
I do not recommend using memset in any form. It will only work with POD types, and it's very easy to break. memset has no place in C++.