为什么需要智能指针
普通指针在资源访问中导致的指针悬空问题
指针悬空问题
#include<iostream>
#include<string>
using namespace std;
class Data {
public:
Data(string str) : _str(str) {
cout << "Constructor" << endl;
}
~Data() {
cout << "Destructor" << endl;
}
void dis() {
cout << _str << endl;
}
private:
string _str;
};
int main() {
Data *pstr1 = new Data("I Love China");
Data *pstr2 = pstr1;
Data *pstr3 = pstr1;
pstr1->dis();
delete pstr1;
pstr2->dis();
return 0;
}
以上程序编译会正常通过,但是因为指针指向的原来的对象已经被释放,所以程序运行时会打印乱码。
指针悬空问题的解决方法
为了解决这个问题,C++中引入了引用计数的概念,引用计数的思想是:每一个对象都有一个引用计数,当有一个指针指向该对象时,该对象的引用计数加1,当指针不再指向该对象时,该对象的引用计数减1,当该对象的引用计数为0时,该对象被释放。
#include<iostream>
#include<string>
using namespace std;
class Data {
public:
Data(string str) : _str(str) {
cout << "Constructor" << endl;
}
~Data() {
cout << "Destructor" << endl;
}
void dis() {
cout << _str << endl;
}
private:
string _str;
};
class Count //Count类用于存储指向同一资源的指针数量
{
public:
friend class SmartPtr;
Count(Data *pdata) : _pdata(pdata), _count(1) {
cout << "Count类构造函数" << endl;
}
~Count() {
cout << "Count类析构函数" << endl;
delete _pdata;
}
private:
Data *_pdata;
int _count;
};
//使用指针实现智能指针
class SmartPtr //SmartPtr类用于对指向Data类对象的指针实现智能管理
{
public:
SmartPtr(Data *pdata) : _reNum(new Count(pdata)) {
cout << "创建基类对象" << endl;
}
SmartPtr(const SmartPtr &another) : _reNum(another._reNum) {
++_reNum->_count;
cout << "Smartptr类复制构造函数" << endl;
}
~SmartPtr() {
if (--_reNum->_count == 0) {
delete _reNum;
cout << "Smartptr类析构函数" << endl;
}
}
Data *operator->() {
return _reNum->_pdata;
}
Data &operator*() {
return *_reNum->_pdata;
}
int disCount() {
return _reNum->_count;
}
private:
Count *_reNum;
};
int main() {
Data *pstr1 = new Data("I Love China!");
SmartPtr pstr2 = pstr1;
(*pstr1).dis();
SmartPtr pstr3 = pstr2;
pstr2->dis();
cout << "使用基类对象的指针数量:" << pstr2.disCount() << endl;
return 0;
}
以上代码实现了一件事,就是在所有包含原始对象Data的包装对象都被析构之后再释放原始的Data对象,类似于默认拷贝构造函数中的浅拷贝。
这就是智能指针的核心原理。