How to Do the Equivalent of Memset(This, ...) Without Clobbering the Vtbl

Using memset to clear base class members

BaseStruct has no virtual member, so you should be good. vtbl should be for BaseA. However, better would be if could reset each individual member explicitly. That's recommended.

zeroing derived struct using memset

This assumes that the Base base class subobject is located at the beginning of Derived. This won't work if you add another base class.

Further, your code is wrong: pointer arithmetic is performed in terms of objects, not in terms of bytes. You need to use reinterpret_cast<char*>(this) to perform the arithmetic in terms of bytes. In any case, you still shouldn't do this.

Consider the following, non-ugly, standards-conforming approach utilizing value initialization:

struct Derived : public Base
{
struct DerivedMembers { /* ... */ }

DerivedMembers data;

Derived() : data() { }
};

As long as DerivedMembers has no constructor, this will value initialize each of the data members of data, which look like it's exactly the behavior you want.

Or, if you want the members to be accessible without using a "data" member variable, consider using another base class:

struct DerivedMembers { /* ... */ }

struct Derived : Base, DerivedMembers
{
Derived() : DerivedMembers() { }
};

Should C++ programmer avoid memset?

The issue is not so much using memset() on the built-in types, it is using them on class (aka non-POD) types. Doing so will almost always do the wrong thing and frequently do the fatal thing - it may, for example, trample over a virtual function table pointer.

C memset seems to not write to every member

No don't use memset -- it zeroes out the size of a pointer (4 bytes on my x86 Intel machine) bytes starting at the location pointed by this. This is a bad habit: you will also zero out virtual pointers and pointers to virtual bases when using memset with a complex class. Instead do:

template <class T>
class vector2
{
public:
// use initializer lists
vector2() : x(0), y(0) {}
T x;
T y;
};

in c++11, can you always (safely) replace a memset() initialization with an empty initializer?

You can certainly initialize any standard layout type using empty parenthesis and get it zero initialized. Once you add constructors into the picture, this isn't necessarily true, unfortunately:

struct foo {
int f;
};
struct bar {
int b;
bar() {}
};

foo f{};
bar b{};

While f.f is zero initialized, b.b is uninitialized. However, there isn't anything you can do about bar because you can't memset() it either. It needs to be fixed.

C++: Fastest way to initialize class object to 0

There is no "magic" syntax to achieves this.

If the class has no virtual table, you could use memset(this, 0, sizeof(* this)), but it is not recommended.

You could try to play with offsetof to pinpoint the address of the first member, and erase from there on. This is a bit better than simply memseting the whole thing, but it is still making me uncomfortable:

// Example non-POD type.
class B
{
public:
B() : b(0xDEADBEEF) {}
int b;
};

class Monstrosity
{
public:
Monstrosity()
{
size_t offset = offsetof(Monstrosity, a);
uint8_t *eraseStart = (uint8_t *)this + offset;
memset(eraseStart, 0, sizeof(Monstrosity) - offset);
}

virtual int foo() { return 0; }

int a;
B b;
};

If any if your members has a virtual table, you're practically screwed.



Related Topics



Leave a reply



Submit