开发者

Object initialization

开发者 https://www.devze.com 2023-01-25 16:12 出处:网络
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 virt

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 avoi开发者_如何学Pythond 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.


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.


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;
}


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;
}


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.


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

0

精彩评论

暂无评论...
验证码 换一张
取 消