对象初始化

时间:2010-11-16 20:24:52

标签: c++ initialization virtual

我在嵌入式软件上工作。以前我们不使用太多的C ++特性,因此我们使用memset(this,0,sizeof(child))来初始化(清零)一个对象。但是由于我们使用虚函数,它现在不起作用。显然它会破坏vtable /虚拟指针。

所以我的问题是: 如何快速方便地初始化对象?

类子继承自父类,它定义了很多虚函数,并获得了许多数据成员。如果我只需要将所有数据成员清零,那么在不使用memset()的情况下,可以避免在子构造函数中使用member-by-memeber赋值吗?或任何使用memset而不破坏vtable的技巧? (与编译器无关的方式)

非常感谢。

5 个答案:

答案 0 :(得分:4)

您要求使用C ++的功能,但不希望每个成员初始化的性能受到影响。首先,我会问自己这是否真的是你正在谈论的热门话题。除了将成员设置为0之外,还有很多瓶颈可供查找。

但是,如果您想要C ++的功能并且仍然希望memset()的速度,那么我建议您将此类的数据放在不同的类中并将其初始化为0并将其传递给类将通过参考使用它。

答案 1 :(得分:4)

使用placement new绝对是一个避免成员明智地清除内存的选项。使用delete []删除内存。

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

答案 2 :(得分:3)

免责声明:这是一个廉价而肮脏的黑客,不是非常C ++,而仇恨者会讨厌它。但是,嘿。如果你要做你必须做的事情,你必须做的是POD,那么这将有效。

如果您可以将您想要的数据成员memset并将它们放入自己的POD中,则可以设置该POD。即(这里讨论的POD是BucketOBits结构):

注意:此处使用的数据类型是POD(普通旧数据)非常重要。有关这意味着什么的更多信息,请参阅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;
}

更好的是,您可以使用以下事实:对于整数类型的值初始化意味着零初始化,并完全摆脱memset,同时可能甚至使您的代码比使用memset快一点。在构造函数的初始化中使用BucketOBits的默认构造:

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

EDIT2:

如果基数和派生类具有需要此零init的数据成员,然后您仍然可以通过为每个类提供它自己的BucketOBits来使用此方法。一个很好的例子:

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

答案 3 :(得分:2)

首先,您无法避免使用构造函数,因为在创建对象时会自动调用它。如果您自己没有定义构造函数,编译器将为您定义一个构造函数。当你调用memset(this)时,你应该永远不会做BTW,那么构造函数已经被调用了。

其次,在C ++中初始化和赋值并不完全相同。初始化实际上更快,这就是为什么你应该在构造函数的初始化列表中初始化数据成员,而不是在构造函数体中为它们赋值。

简而言之,我建议你不要对抗语言。

答案 4 :(得分:1)

  

没有使用memset的任何技巧   摧毁vtable?   (与编译器无关的方式)

没有办法独立解决这个平台问题 原因是vtable没有放在特定地址中,而是可以在对象的开头,或者在最后一个数据成员之后。因此,开始计算地址并跳过它是不可移植的。指针的大小也取决于架构等。
对于多重继承,它会变得更糟 您应该使用初始化列表(不是构造函数中的赋值)或新的位置 正如Chubsdad的回答。

  

如果我只需要将所有数据归零   会员,任何避免的方式   按成员分配   没有使用的孩子的构造函数   memset的()?

你不能(也绝不能)避免在这个上下文中调用构造函数,因为它是初始化vtable指针的构造函数