堆内存的对象需要手动delete销毁,如果忘记使用delete销毁就会造成内存泄漏。
所以在C++ ISO 98标准中引入了智能指针的概念,并且在ISO11中趋于完善。
使用智能指针可以让堆内存对象具有栈内存对象的特性。原理时给需要自动回收的堆内存对象套上一个栈内存对象的模板。
C++有四种智能指针:
● auto_ptr 自动指针(C++ ISO 98 已废弃)
● unique_ptr 唯一指针(C++ ISO 11)
● shared_ptr 共享指针(C++ ISO 11)
● weak_ptr 协助指针(C++ ISO 11)
智能指针头文件,#include
#include
#include
using namespace std;
class Test
{
private:
string s;
public:
Test(string s):s(s)
{
cout << s << "构造函数" << endl;
}
~Test()
{
cout << s << "析构函数" << endl;
}
void show()
{
cout << s << "执行程序" << endl;
}
};
int main()
{
{
Test *t1 = new Test("A");
// 创建一个栈内存智能指针对象ap1
auto_ptr ap1(t1); // ap1 管理t1
// 取出被管理的堆内存对象,并调用show成员函数
ap1.get()->show();
// 释放ap1智能指针对t1对象的控制权
// ap1.release();
// 创建B堆对象,B把A顶掉,A对象销毁
ap1.reset(new Test("B"));
ap1.get()->show();
ap1.reset();
cout << "局部代码块执行结束" << endl;
}
cout << "程序运行结束" << endl;
return 0;
}
由于成员变量存在指针类型,因此拷贝构造函数与赋值运算符的使用会出现问题。与浅拷贝不同的是,auto_ptr的复制语义会引起资源对象控制权转移的问题。
#include
#include
using namespace std;
class Test
{
private:
string s;
public:
Test(string s):s(s)
{
cout << s << "构造函数" << endl;
}
~Test()
{
cout << s << "析构函数" << endl;
}
void show()
{
cout << s << "执行程序" << endl;
}
};
int main()
{
{
auto_ptr ap1(new Test("A"));
auto_ptr ap2(ap1); // 显示调用构造函数
cout << ap1.get() << " " << ap2.get() << endl; // 0 0xf427b8
auto_ptr ap3 = ap2; // 隐式调用构造函数
cout << ap1.get() << " " << ap2.get() << " "<< ap3.get() << endl; // 0 0 0x10927b8
auto_ptr ap4;
ap4 = ap3; // 赋值运算符
cout << ap1.get() << " " << ap2.get() <<
" "<< ap3.get() << " " << ap4.get() << endl; // 0 0 0 0x10527b8
}
cout << "程序运行结束" << endl;
return 0;
}
作为auto_ptr的改进,unique_ptr堆其他持有的资源对象具有唯一的控制权,即不可以通过常规的复制语法转移或者拷贝资源对象的控制权。
#include
#include
using namespace std;
class Test
{
private:
string s;
public:
Test(string s):s(s)
{
cout << s << "构造函数" << endl;
}
~Test()
{
cout << s << "析构函数" << endl;
}
void show()
{
cout << s << "执行程序" << endl;
}
};
int main()
{
{
unique_ptr ap1(new Test("A"));
unique_ptr ap2(move(ap1)); // 显示调用构造函数
cout << ap1.get() << " " << ap2.get() << endl; // 0 0xf427b8
unique_ptr ap3 = move(ap2); // 隐式调用构造函数
cout << ap1.get() << " " << ap2.get() << " "<< ap3.get() << endl; // 0 0 0x10927b8
unique_ptr ap4;
ap4 = move(ap3); // 赋值运算符
cout << ap1.get() << " " << ap2.get() <<
" "<< ap3.get() << " " << ap4.get() << endl; // 0 0 0 0x10527b8
}
cout << "程序运行结束" << endl;
return 0;
}
unique_ptr对资源具有独占性,多个shared_ptr对象可以共享资源。
shared_ptr有两种创建方式。
两种创建方式的区别在于后者是一部实现(创建资源对象+关系绑定)。前者分为(先创建资源对象,再关系绑定)。
后者优点:
● 安全性更好
● 性能更高
后者缺点:
● 释放资源的效率低。
每次多一个shared_ptr对资源进行管理,引用计数+1,每个指向该对象的shared_ptr对象销毁时,引用计数-1.最后一个shared_ptr对象销毁时,计数清零,资源对象销毁。
#include
#include
using namespace std;
class Test
{
private:
string s;
public:
Test(string s):s(s)
{
cout << s << "构造函数" << endl;
}
~Test()
{
cout << s << "析构函数" << endl;
}
void show()
{
cout << s << "执行程序" << endl;
}
};
int main()
{
shared_ptr sp3;
{
shared_ptr sp1(new Test("A"));
cout << "引用计数:" << sp1.use_count() << endl; // 1
shared_ptr sp2(sp1); // 拷贝构造函数
cout << "引用计数:" << sp2.use_count() << endl; // 2
sp3 = sp2;
cout << "引用计数:" << sp2.use_count() << endl; // 3
}
cout << "引用计数:" << sp3.use_count() << endl; // 1
sp3.get()->show();
cout << "程序运行结束" << endl;
return 0;
}
weak_ptr是一个不控制资源对象的智能指针,也不会影响资源的引用计数。其主要目的是协助shared_ptr工作。
通过weak_ptr的构造函数,参数传入一个持有资源对象的shared_ptr对象或weak_ptr对象,即可创建.
weak_ptr与资源对象呈弱相关性,因此不支持get等函数直接操作资源对象.
建议weak_ptr调用lock函数之前,先检测引用计数是否大于0,或使用expired()函数检测是否可转换为shared_ptr.
#include
#include
using namespace std;
class Test
{
private:
string s;
public:
Test(string s):s(s)
{
cout << s << "构造函数" << endl;
}
~Test()
{
cout << s << "析构函数" << endl;
}
void show()
{
cout << s << "执行程序" << endl;
}
};
int main()
{
weak_ptr wp3;
{
shared_ptr sp1(new Test("A"));
weak_ptr wp1 = sp1;
cout << sp1.use_count() << endl;
cout << wp1.use_count() << endl;
weak_ptr wp2(wp1); // 拷贝构造
cout << wp2.use_count() << endl;
// 从weak_ptr中得到一个只有资源的shared_ptr对象
shared_ptr sp2 = wp1.lock();
cout << sp2.use_count() << endl;
shared_ptr sp3 = wp1.lock();
cout << sp3.use_count() << endl;
wp3 = wp1;
cout << wp3.use_count() << endl;
if(wp3.expired())
{
cout << "无法使用lock函数" << endl;
}
else
{
cout << "可以使用lock函数" << endl;
}
}
cout << wp3.use_count() << endl; // 0
if(wp3.expired())
{
cout << "无法使用lock函数" << endl;
}
cout << "程序运行结束" << endl;
return 0;
}