前几天我写的代码中错用了memcpy函数,作个总结,以免大家犯同样的错误。
错误使用时的环境模拟:
基类:CBase
Class CBase
{
public:
double m_nF;
virtual void Func(void) = 0;
};
派生类:CDeriveA、CDeriveB
class CDeriveA : public CBase
{
public:
double m_nA;
virtual void Func(void) {};
};
class CDeriveB : public CBase
{
public:
double m_nB;
virtual void Func(void) {};
};
指针 CBase* pBase;
已知pBase所指的对象是CDeriveA类型。
CDeriveA objDerA;
pBase = (CBase*)objDerA;
需要复制一个跟pBase所指对象一模一样的对象。考虑到简便和高效:
int _size = sizeof(CBase);
CDeriveA* pDevA = (CDeriveA*)_alloca(_size); // _alloca函数是一个在栈上分配内存空间的函数,不用手动释放内存
memcpy(pDevA, pBase, _size);
这样做会引发很严重的错误:
1 一般来讲,派生类所占空间比基类要大,所以
memcpy(pDevA, pBase, _size)
拷贝的数据不全。
当访问pDevA->m_nA时,值是未知的。
更为严重的是,如果pDevA所指的对象并不是CDeriveA类型,那么有赋值操作如 pDevA->m_nA=xxx时,将会破坏跟pDevA所指对象相邻的内存中的信息。而此内存中所存的是什么信息,我们并不知道。如果恰巧是一些地址,那么我们的函数将可能乱套L
2 如果pBase原本所指的对象就不是CDeriveA类型而是CDeriveB类型,那么memcpy将会将对象类型信息和虚函数表的地址也一同复制。
此时如果调用pDevA->Func(),调用的将不是CDeriveA::Func()而是CDeriveB::Func()。
3 对C++和Computer,我认识尚浅,如有不对的地方,请指正。特别是对函数调用时的堆栈操作,C++的虚函数表的作用很使用等,请教。