c++ void*指针理解和应用
void*说明
void指针不指向任何数据类型,它属于一种未确定类型的过渡型数据。如果要访问实际存在的数据,必须将void指针强转成为指定一个确定的数据类型的数据,如int*、string*、Person*等。
void* p=nullptr;
int *a=nullptr;
p=a;
double *b=nullptr;
p=b;
Person *per = new Person;
p = per;
char c[16]={0};
p=c;
void* 就像一张白纸,任何类型的指针都可以直接赋值给void*类型的指针;
但是反过来
int *a=nullptr;
a=p; //err
a=(int *)p;//需要强制类型转换
Person *person2 = nullptr;
person2 = (Person *)p;
2.void指针只支持几种有限的操作:
a.与另一个指针进行比较;
b.向函数传递void指针或从函数返回void指针;
c.给另一个void指针赋值。
3.不允许使用void指针操作它所指向的对象,例如,不允许对void指针进行解引用。不允许对void*指针进行算术操作。例如:
几种常用的应用
1.函数传参时不确定类型,或者要支持多类型的传参
void function(int dataType, void* data) {
// 根据dataType的不同值,进行不同的转换
switch (dataType) {
case 0:
int* a = (int*)data;
case 1:
char* a = (char*)data;
...
}
}
2.当函数的返回值不考虑类型指关心大小的时候
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
//memcpy和memset对外接收任何类型的指针,这样是合理并且必要的,因为这是内存操作函数,
//是对bit进行操作的,考虑数据类型是没有任何意义的。
*2.关于delete void指针
1.void指向简单的系统内建类型直接只用delete void,比如下面代码所示:
void* p=nullptr;
int *a=nullptr;
p=a;
double *b=nullptr;
p=b;
delete p;
2.void*所指向的对象在析构函数里要释放,进行此造作会丢失内存,因为它不执行析构函数,比如下面以下代码
class CEntity
{
public:
CEntity(char flag);
void setData(void *data);
void setFlag(char flag);
~CEntity();
private:
void * m_data;
char m_flag;
};
CEntity::CEntity(char flag)
{
m_flag = flag;
cout<<"constructing entity "<<m_flag<<endl;;
}
void CEntity::setData(void *data)
{
m_data = data;
}
void CEntity::setFlag(char flag)
{
m_flag = flag;
}
CEntity::~CEntity()
{
cout<<"destructing entity "<<m_flag<<endl;
delete m_data;
}
//以上这个类是没什么问题的,但是看以下的调用:
int main(int argc, char *argv[])
{
CEntity * a = new CEntity();
int ivalue = 5;
int *pivalue = &ivalue;
a->setFlag(true);
a->setData(pivalue);
delete a;
CEntity * b = new CEntity();
int ivalue2 = 6;
int *pivalue2 = &ivalue2;
b->setFlag(true);
b->setData(pivalue2);
void *vb = b;
delete vb;
return 0;
}
我们关心他的输出:
其输出为:
constructing entity a
destructing entity a
constructing entity b
可见,delete b 的时候没有释放m_data所指向的内存,没有执行析构函数。
这样会造成内存泄漏。
那么如何释放指向对象类型的void*指针呢?需要强制转换类型,然后进行delete。
```cpp
CEntity * b = new CEntity('b');
int ivalue2 = 6;
int *pivalue2 = &ivalue2;
b->setData(pivalue2);
void *vb = b;
//delete vb;
delete (CEntity*)vb;
其输出为:
constructing entity a
destructing entity a
constructing entity b
destructing entity b
如果b对象的setData(a)这样使用,如何释放b对象内存呢、答案是b对象可以正常调用析构函数,但是其成员变量void指向的a对象内存永远释放不掉。因为delete a时会调用a的析构函数,在析构函数中本身类不知道void的真正的类型,所以delete void*时不会调用b的析构函数。代码和程序结果运行如下:
int main(int argc, char *argv[])
{
CEntity * a = new CEntity('a');
int ivalue = 5;
int *pivalue = &ivalue;
a->setData(pivalue);
CEntity * b = new CEntity('b');
b->setData(a);
void *vb = b;
delete (CEntity*)vb;
return 0;
}
其输出为:
constructing entity a
destructing entity a
constructing entity b
故类中的成员尽可能避免使用void变量,否则在类对象指针传入时会造成析构时void无法正确释放。