为什么会有 “监测指针是否被释放” 的需求?
//声明一个int指针
int *p1 = new int;
//给指向的值赋值
*p1 = 255;
//声明一个int指针的数组,数组大小为1
int**pArray = new int*[1];
//把 p1 指针的值拷贝到 pArray[0]
memmove(&pArray[0], &p1, sizeof(p1));
//输出:address: 000001F49D79B1F0 value : 255,正常
cout << "address: " << pArray[0] << " value: " << *pArray[0] << endl;
if (p1 != nullptr) {
delete p1;
p1 = nullptr;
}
//输出:address: 000001F49D79B1F0 value: -572662307,可见内存已被释放
cout << "address: " << pArray[0] << " value: " << *pArray[0] << endl;
if (pArray[0] != nullptr) {
//输出:"pArray[0] is not a nullptr,but can not be deleted!\n"
cout << "pArray[0] is not a nullptr,but can not be deleted!\n";
}
delete pArray[0];//报错:
可见,如果指针的值从A处被拷贝到了B处,是不能通过 nullptr 来判断指针指向的内存释放被释放;如果访问了被释放的内存,一是结果不对,二是访问冲突。
当考虑使用boost的无锁队列时,如此声明 queue<int* > intPtrQueue;
,当push 的时候就是把指针的值拷贝到队列里了。
当然这个问题应该是智能指针能解决的问题,但是不会,所以先不用。
于是把指针封装一下:
class intPtr {
private:
int* i_p;
bool isUsing;
public:
intPtr (int val) {
Init(val);
}
void Init(int val) {
i_p = new int;
*i_p = val;
isUsing = true;
}
void setVal(int val){
*i_p = val;
}
void Delete() {
if(i_p!= nullptr){
delete i_p;
i_p= nullptr;
}
isUsing = false;
}
bool Using() {
return isUsing;
}
};
声明一个对象 intPtr *intptr = new intptr (255)
当需要释放 intptr
时,调用intptr->Delete()
释放内部申请的 int ,当别处需要使用 intptr
先判断intptr->Using()
的真假,然后再做操作。
当最后需要释放所有intPtr
类型的对象时,先判断intptr->Using()
的真假,真则先释放内部内存,再删除对象 ;假则直接删除对象。
总结一下:
1.intPtr 是一个壳子,里面装一个指针,壳子常在,而指针通过Init(int), Delete()
发生改变;
2.指针可以是任意类型的指针;
3.在生产者和消费者模型中,特化为以下情形:
a.对n个生产者,声明n个壳子(intPtr),生产者把生成的数据的指针(本例是直接传int值)赋值给壳子,而同时生产者又拥有操作壳子的权利。操作时应该加锁 ;
b.壳子push到队列queue0,壳子中应有标志位表示壳子位于哪个队列,设为queue_id = 0;
c.消费者从queue1 pop,处理、展现、生成结果,把 queue_id = -1;
d.每个生产者通过判断 queue_id 来判断是否可以(需要)更新数据的指针所指向的数据,或释放之前的数据,来申请新的数据。
e.当生产者需要自己结束自己,或被用户要求结束时,调用Delete(),消费者可以得知壳中指针指向的内存已经不可访问,则在pop后释放壳子。