- 指针的危害
指针未初始化
野指针
内存泄漏
智能指针的出现就是为了解决上面的问题。
智能指针基于这样的事实得以发挥作用:定义在栈中的智能指针,当超出其作用域时,会自动调用它的析构函数,从而可以释放其关联的内存资源。
智能指针 | 进入C++标准的版本 | STL头文件 | boost头文件 | 说明 |
---|---|---|---|---|
auto_ptr | C++03 |
|
| 尽量避免使用 |
unique_ptr | C++11 |
|
| 管理单个堆内存对象,独享所有权,不允许赋值和拷贝,不能用于管理数组对象 |
shared_ptr | C++11 |
|
| 引用计数智能指针,共享所有权 |
weak_ptr | C++11 |
|
| shared_ptr 的观察者,只进行引用而不改变引用计数,用来解决shared_ptr的循环引用问题 |
scoped_ptr | - | - |
| 作用域智能指针,功能与unique_ptr 相似。 |
- 本质:
将指针封装为类对象成员,并在析构函数里删除指针指向的内存。 - 不同:
auto_ptr
、unique_ptr
、scoped_ptr
马上删除。
shared_ptr
计数为0删除。
weak_ptr
不删除。
auto_ptr
- 作用
对作用域内的动态分配对象的自动释放 - 基本类型
#include
#include
using namespace std;
int main(){
int* pn = new int(10);
auto_ptr<int> ap(pn);
cout << *ap << endl;
}
- 类类型
#include
#include
using namespace std;
class Test{
public:
Test(){cout << __func__ << endl;}
~Test(){cout << __func__ << endl;}
void Func(){cout << __func__ << endl;}
};
int main(){
Test* pt = new Test;
auto_ptr<Test> apt(pt);
apt->Func();
}
- 缺陷
(1)两个auto_ptr
不能同时拥有同一个对象
#include
using namespace std;
int main(){
int* pn = new int(10);
auto_ptr<int> ap1(pn);
auto_ptr<int> ap2(pn);
}
(2)auto_ptr
不能管理数组指针
#include
using namespace std;
int main(){
int *pa=new int[10];
auto_ptr<int>ap(pa);
}
(3)auto_ptr
被拷贝或被赋值后,失去对原指针的管理,这种情况被称为指针所有权传递。
a)赋值的情况
- 实例
#include
#include
using namespace std;
int main(){
int* p = new int(10);
auto_ptr<int> ap1(p);
cout<< *ap1 <<endl;
auto_ptr<int> ap2=ap1;
cout<< *ap1 <<endl;
}
b)拷贝的情况
- 实例
#include
#include
using namespace std;
void Func(auto_ptr<int> ap){
cout << *ap << endl;
}
int main(){
int* p = new int(10);
auto_ptr<int> ap(p);
cout<< *ap <<endl;
Func(ap);
cout<< *ap <<endl;
}
auto_ptr不能作为容器对象,因为STL容器中的元素经常要支持拷贝,赋值等 *** 作。
#include
#include
#include
using namespace std;
int main(){
int*p = new int(10);
auto_ptr<int> ap(p);
vector<auto_ptr<int> > vec;
vec.push_back(ap);
}
(4)auto_ptr
不能作为容器对象,因为STL容器中的元素经常要支持拷贝,赋值等 *** 作。
#include
#include
#include
using namespace std;
int main(){
int*p = new int(10);
auto_ptr<int> ap(p);
vector<auto_ptr<int> > vec;
vec.push_back(ap);
}
- 实例
#include
#include
using namespace std;
class Test{
public:
Test(){cout << __func__ << endl;}
~Test(){cout << __func__ << endl;}
void func(int n)const{
cout << n << endl;
}
};
namespace MySTL{
template <typename T>
class auto_ptr{
T* p;
public:
auto_ptr(T* p):p(p){}
~auto_ptr(){
delete p;
}
T* operator->(){
return p;
}
T& operator*(){
return *p;
}
};
};
int main(){
Test* pp = new Test;
MySTL::auto_ptr<Test> p(new Test); //p智能指针
p->func(10);
p.operator->()->func(100); //p.operator->()返回的是p指针
(*p).func(100);
delete pp;
int* arr = new int [10];
delete [] arr;
}
结果:
Test
Test
10
100
100
~Test
~Test
分析:将指针封装为类对象成员,并在析构函数里删除指针指向的内存。
5.3 unique_ptr- 作用
代替auto_ptr
,不可复制与赋值。
scoped_ptr
- 作用
与unique_ptr
相似,在本作用域中使用,不能复制与赋值。
shared_ptr
-
作用
解决unique_ptr
禁用拷贝以及auto_ptr
的缺陷 -
实例
#include
#include
using namespace std;
class Test {
public:
Test() {
cout << __func__ << endl;
}
~Test() {
cout << __func__ << endl;
}
void func(int n)const {
cout << n << endl;
}
};
namespace MySTL {
template <typename T>
class auto_ptr {
T* p;
public:
auto_ptr(T* p):p(p) {}
~auto_ptr() {
delete p;
}
T* operator->() {
return p;
}
T& operator*() {
return *p;
}
};
template<typename T>
class shared_ptr {
struct Record {
T* p;
int count;
};
Record* record;
public:
shared_ptr(T* p) {
record = new Record{p,1};
}
shared_ptr(const shared_ptr& ptr) {
record = ptr.record;
++record->count;
}
T* operator->() {
return record->p;
}
T& operator*() {
return *(record->p);
}
shared_ptr& operator=(const shared_ptr& ptr) {
if(this == &ptr) return *this;
if(record->p == ptr.record->p) return *this;
--record->count;
if(record->count == 0) {
delete record->p;
delete record;
}
record = ptr.record;
++record->count;
return *this;
}
~shared_ptr() {
--record->count;
if(0 == record->count) {
delete record->p;
delete record;
}
}
};
};
int main() {
// Test* pp = new Test;
MySTL::shared_ptr<Test> p(new Test); //p智能指针
p->func(10);
p.operator->()->func(100); //p.operator->()返回的是p指针
(*p).func(100);
// delete pp;
// int* arr = new int [10];
// delete [] arr;
MySTL::shared_ptr<Test> p2 = p;
p2->func(300);
p->func(400);
MySTL::shared_ptr<Test> p3(new Test);
p3 = p;
p3->func(500);
}
结果:
Test
10
100
100
300
400
Test
~Test
500
~Test
分析:
通过加入Record
记录指向该块内存的指针数量,在析构时候避免重复释放内存。
- 存在的问题:循环引用问题
- 实例
#include
#include
using namespace std;
class A;
class B;
class A{
public:
shared_ptr<B> pb;
A (){
cout << __func__ << endl;
}
~A (){
cout << __func__ << endl;
}
};
class B{
public:
shared_ptr<A> pa;
B (){
cout << __func__ << endl;
}
~B (){
cout << __func__ << endl;
}
};
int main(){
shared_ptr<A> a(new A);
shared_ptr<B> b(new B);
//A和B出现循环引用
a->pb = b;
b->pa = a;
}
结果:
A
B
分析:
只构造不析构,A和B出现循环引用
weak_ptr
- 作用
解决shared_ptr
循环引用问题 - 实例
#include
#include
using namespace std;
class A;
class B;
class A{
public:
weak_ptr<B> pb;
A (){
cout << __func__ << endl;
}
~A (){
cout << __func__ << endl;
}
};
class B{
public:
weak_ptr<A> pa;
B (){
cout << __func__ << endl;
}
~B (){
cout << __func__ << endl;
}
};
int main(){
shared_ptr<A> a(new A);
shared_ptr<B> b(new B);
//A和B出现循环引用
a->pb = b;
b->pa = a;
}
结果:
A
B
~B
~A
智能指针weak_ptr
主要用来协助shared_ptr
。不参与引用计数,但是有以下好处:
1 打破递归的依赖关系
2 使用一个共享的资源但是不要所有权,不添加引用计数
3 避免悬空指针。
- 智能指针的特点
智能指针 | 管理同一个对象 | 可拷贝 | 可复制 | 所有权 | 成为容器元素 | 管理数组指针 |
---|---|---|---|---|---|---|
auto_ptr | NG | OK | OK | 传递 | NG | NG |
unique_ptr | NG | NG | NG | 独享 | NG | NG |
scoped_ptr | NG | NG | NG | 独享 | NG | NG |
shared_ptr | NG | OK | OK | 共享 | OK | NG |
weak_ptr | NG | OK | OK | 共享 | OK | NG |
虽然通过弱引用指针可以有效的解除循环引用,但这种方式必须在程序员能预见会出现循环引用的情况下才能使用,也可以是说这个仅仅是一种编译期的解决方案。
如果程序在运行过程中出现了循环引用,还是会造成内存泄漏的。
因此,不要认为只要使用了智能指针便能杜绝内存泄漏。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)