c++ void*指针理解和应用

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无法正确释放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值