2

I works on embedded software. Previously we don't use too many C++ features so we use memset(this,0,sizeof(child)) to initialize(zero out) a object. However it doesn't work now since we are using virtual functions. Apparently it would destroy the vtable/virtual pointer.

So my question is: How can I initialize an object quickly and conveniently?

The class child inherits from class parent, which defines a lot virtual functions, and got many data member. If I need only to zero out all data member, any way to avoid member-by-memeber assignment in child's constructor without using memset()? or any trick to use memset without destroying vtable? (compiler-independent way)

Thank you very much.

Solti
  • 21
  • 1

5 Answers5

4

You're asking to utilize the facilities of C++ but don't want the performance-hit of per-member initialization. Firstly, I'd ask myself if this is really the hit you're talking about. There are plenty of more bottlenecks you can be looking for than setting a member to 0.

But, if you want the features of C++ and still want the speed of memset() then I suggest you put the data for this class in a different class and initialize that to 0 and pass it to the class that is going to use it by reference.

Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
  • I don't think Solti mentioned anything about a performance hit, simply not wanting to do it – slf Nov 16 '10 at 20:33
  • 1
    @slf, I took `So my question is: How can I initialize an object quickly and conveniently?` as a hint that this thing needed to be fast :) probably me reading too much in to it, admittedly. – Moo-Juice Nov 16 '10 at 20:37
4

Using placement new is definitely an option to avoid member wise zeroing out memory. Use delete[] to delete memory.

struct base{virtual ~base(){}};
struct derived : base{};

int main() 
{
   char *p = new char[sizeof(derived)];
   memset(p, 0, sizeof(derived));
   derived *pd = new (p) derived;
}
Chubsdad
  • 24,777
  • 4
  • 73
  • 129
  • 1
    Placement new will still call the constructor. There is no way to not have it called. – Dima Nov 16 '10 at 20:33
  • @Dima: Yes, that's true. Should have mentioned that. – Chubsdad Nov 16 '10 at 20:37
  • @Dima: There most certainly *is* a way of creating objects without having the constructor called. – OJ. Nov 16 '10 at 20:38
  • Only if you use a c-style cast or `reinterpret_cast`. But that is not really "creating" an object. This is treating a chunk of memory as the object, and it can very easily backfire. – Dima Nov 16 '10 at 20:41
  • @Dima:Actually if you call malloc instead of new, the constructor will not be called. new calls first malloc then initializes the object via constructor. malloc is not aware of constructors – Cratylus Nov 16 '10 at 20:47
  • @user: If you call `malloc`, you are not creating an object, you are allocating a memory buffer. Then you would have to cast the pointer using a c-style cast or `reinterpret_cast`. And if you cast it to anything that is not POD you are likely to have major problems. There is a reason why the use of c-style casts and even `reinterpret_cast` in C++ is frowned upon. – Dima Nov 16 '10 at 20:50
  • @Dima:What is object creation? Memory allocation + initialization via constructor. Malloc is constructor unaware and does only the alloction.New also calls constructor. C style cast is still legal. I think you are overstating here. – Cratylus Nov 16 '10 at 21:05
  • I realize that this is circular: if object creation is allocation + construction, then just allocation is not creation. What I am trying to emphasize here is that if you have virtual functions and/or (multiple) inheritance, and you try to do allocation via malloc and then cast, then your program will not work corrently, and will likely crash. Although it will compile just fine. – Dima Nov 16 '10 at 21:10
  • @Dima:This is obvious since the initialization of vtable is in the constructor.I just mentioned a way to create a usable object without calling the constructor. I didn't say it is recommended to all, or that it works in all cases. But the poster does not want to avoid calling constructor, so I am not sure why these comments started in the first place :) – Cratylus Nov 16 '10 at 21:14
  • The question says "...any way to avoid member-by-memeber assignment in child's constructor..." – Dima Nov 16 '10 at 21:18
3

DISCLAIMER: This is a cheap and dirty hack, not very C++ish, and haters will hate it. But hey. If you gotta do what you gotta do, and what you gotta do it to is a POD, then this will work.

If you can take the data members that you want to memset and put them in their own POD, you can memset that POD. To wit (the POD in question here is the BucketOBits struct):

NOTE: It is important that the datatype you use here is a POD (Plain Old Data). For more about what this means, see this FAQ entry.

#include <cstdlib>
#include <cstring>


class Interface
{
public:
    virtual void do_it() const = 0;
    virtual ~Interface() {};
};

class Object : public Interface
{
public:
    Object();
    void do_it() const {};
private:
    struct BucketOBits
    {
        int int_a_;
        int int_b_;
        int int_c_;
    } bucket_;
};

Object::Object() 
{   
    memset(&bucket_, 0, sizeof(bucket_));
};

int main()
{
    Interface* ifc = new Object;
}

Even better, you can use the fact that value initialization for integral types means zero-initialization, and get rid of the memset entirely, while at the same time maybe even making your code a little faster than if you had used memset. Use default construction for BucketOBits in the constructor's initialization:

Object::Object() : bucket_()
{   
};

EDIT2:

If both base & derived classes have data members that need this zero-init, then you can still use this method by giving each class it's own BucketOBits. Case in point:

#include <cstdlib>
#include <cstring>


class Interface
{
public:
    virtual void do_it() const = 0;
    Interface();
    virtual ~Interface() {};
private:
    struct BucketOBits
    {
        unsigned base_int_a_;
        unsigned base_int_b_;
        long base_int_c_;
    } bucket_
};

class Object : public Interface
{
public:
    Object();
    void do_it() const {};
private:
    struct BucketOBits
    {
        int int_a_;
        int int_b_;
        int int_c_;
    } bucket_;
};

Interface::Interface() : bucket_() 
{
}

Object::Object() : bucket_()
{   
}

int main()
{
    Interface* ifc = new Object;
}
Community
  • 1
  • 1
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • This is fine, but how is this related to the post? You have just declared a class that has a struct as data member and you zero it out. Fine. But he wants to know about object having several fields, some inherited also. Are you suggesting to change his class members to structs? – Cratylus Nov 16 '10 at 21:10
  • @user: As I said in my post, "If you can take the data members that you want to memset and put them in their own POD [...]" *if* OP can do this, then he can use my method. If not, then he can't. He can even do this all the way up & down the inheitance tree. I'll edit my answer to reflect this. – John Dibling Nov 16 '10 at 21:13
  • @user: *again* as I said, the struct must be a POD. Please read my post carefully. – John Dibling Nov 16 '10 at 21:23
2

First, you cannot avoid using the constructor, because it will be called automatically when you create the object. If you do not define a constructor yourself, the compiler will define one for you. By the time you call memset(this), which BTW you should never ever do, the constructor has already been called.

Second, in C++ initialization and assignment is not quite the same thing. Initialization is actually faster, which is why you should initialize the data members in the constructor's initialization list, rather then assign values to them in the body of the constructor.

In short, I would advise you not to fight the language.

Dima
  • 38,860
  • 14
  • 75
  • 115
  • If you use the standard mechanisms, yes, your constructor will always be called. But saying "you can't avoid using the constructor" is wrong as a generalisation, because you *can* avoid it. – OJ. Nov 16 '10 at 20:39
  • Ok, I should have qualified it: you cannot create an object using the standard mechanisms without having the constructor be called. However, if you are trying to create an object that is not plain-old-data using non-standard mechanisms you are likely to end up with much bigger problems. – Dima Nov 16 '10 at 21:02
1

any trick to use memset without destroying vtable? (compiler-independent way)

There is no way to work-around this platform independent.
The reason is that vtable not placed in a specific address, but could be in the begining of the object, or right after the last data member. So it is not portable to start calculating addresses and jump over it. Also there is the size of pointer depending on architecture etc.
For multiple inheritance it gets worse.
You should use either an initialization list (not assignment in constructor) or placement new as Chubsdad's answer.

If I need only to zero out all data member, any way to avoid member-by-memeber assignment in child's constructor without using memset()?

You can not (and must not) avoid calling the constructor in this context, since it is the constructor that initializes the vtable pointer

Cratylus
  • 52,998
  • 69
  • 209
  • 339