我在嵌入式软件上工作。以前我们不使用太多的C ++特性,因此我们使用memset(this,0,sizeof(child))来初始化(清零)一个对象。但是由于我们使用虚函数,它现在不起作用。显然它会破坏vtable /虚拟指针。
所以我的问题是: 如何快速方便地初始化对象?
类子继承自父类,它定义了很多虚函数,并获得了许多数据成员。如果我只需要将所有数据成员清零,那么在不使用memset()的情况下,可以避免在子构造函数中使用member-by-memeber赋值吗?或任何使用memset而不破坏vtable的技巧? (与编译器无关的方式)
非常感谢。
答案 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_()
{
};
如果基数和派生类具有需要此零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指针的构造函数