智能指针

智能指针

平时在写代码时,很容易会犯这样的错误

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main()
{
int *p=new int(10);
*p=20;
if(*p==20){ //2.由于new和delete之间的代码逻辑提前结束了
return 0; //3.访问了野指针
} //4.访问了空指针
delete p; //1.有时候忘记了写new对应的delete操作,造成资源泄露
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string>
using namespace std;

//智能指针
//智能:利用栈上的对象,出作用域自动析构的特点,在析构函数中,把管理的外部资源释放掉
//能不能在堆上构造上一个智能指针对象?CSmartPtr<int> *ptr = new CSmartPtr<int>(new int(10));
//智能指针的定义
template<typename T>
class CSmartptr
{
public:
CSmartptr(T *ptr=nullptr):mptr(ptr){}
~CSmartptr()
{
cout<<"~CSmartptr()"<<endl;
delete mptr;
}
//目的为了智能指针和裸指针长得更像,使用起来一样
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
private:
T *mptr;
};

int main()
{
//打印出来自动释放了
CSmartptr<int> ptr1(new int(10));
//int& operator*()
*ptr1=20;
cout<<*ptr1<<endl;

CSmartptr<string>ptr2(new string("hello world"));
cout<<(*ptr2).size()<<endl;
//指向符重载
cout<<ptr2->size()<<endl;
return 0;
}

库里面的智能指针

1.不带引用的计数的智能指针 一个资源只能由一个只能指针指向

1
2
3
4
auto_ptr:拷贝构造、赋值操作=》旧的auto_ptr::mptr全部置成nullptr,只有新的auto_ptr指向合法的资源。
问:auto_ptr能不能用在容器中?vector<auto_ptr<int> >vec;
容器经常做拷贝构造和operator=操作,不能用
unique_ptr:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <string>
#include <memory> //包含C++库里面所有的智能指针
using namespace std;
int main()
{
auto_ptr<int>ptr1(new int(0));
*ptr1=20;
cout<<*ptr1<<endl;

auto_ptr<string>ptr2(new string("hello world"));
cout<<ptr2->size()<<endl;

/*auto_ptr<int>ptr3(ptr1);
*ptr3=40;
cout<<*ptr1<<endl;*/
unique_ptr<int>ptr4(new int(10));
cout<<*ptr4<<endl;
//unique_ptr<int>ptr4(ptr4);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <string>
#include <memory> //包含C++库里面所有的智能指针
using namespace std;

template<typename T>
class CSmartptr
{
public:
CSmartptr(T *ptr=nullptr):mptr(ptr){}
~CSmartptr()
{
cout<<"~CSmartptr()"<<endl;
delete mptr;
}
//目的为了智能指针和裸指针长得更像,使用起来一样
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
//unique_ptr做的事情之一
CSmartptr(const CSmartptr&)=delete;
CSmartptr<T>& operator=(const CSmartptr<T>&)=delete;
//unique_ptr做的事情之二
//unique_ptr可以使用在函数调用中,返回一个unique_ptr
CSmartptr(CSmartptr<T> &&src)
{
mptr=src.mptr;
src.mptr=nullptr;
}
CSmartptr<T>& operator=(CSmartptr<T> &&src)
{
mptr=src.mptr;
src.mptr=nullptr;
return *this;
}
private:
T *mptr;
};
struct node
{
int data;
node *next;
};
//很多这样的API接口, 内存泄露,资源泄露 自动释放资源 智能指针
unique_ptr<node> buynode()
{
unique_ptr<node> p(new node());
p->data=0;
p->next=nullptr;
return p;
}
int main()
{
//return p->拷贝构造的过程,而且匹配的是右值引用参数的拷贝构造
unique_ptr<node>ptr =buynode();
cout<<ptr->data<<endl;
return 0;
}

a.unique_ptr把左值引用参数的拷贝构造函数和operator=函数给delete掉了,但是它提供了带右值引用参数的拷贝构造函数和operator=函数,为什么?这样做有什么用处???

b.为什么带引用计数的智能指针要提供两个,一个不行吗?

2.带引用计数的智能指针 一个资源可以由多个智能指针指向

1
2
shared_ptr:
weak_ptr:

看下shared_ptr使用

shared_ptr(强智能指针):代码上如果只使用shared_ptr,会发生什么问题?智能指针的交叉引用问题???那它该怎么解决呢???

发生了资源泄露,这时候引入弱智能指针

定义对象的时候用强智能指针,引用对象时用弱智能指针,weak_ptr只是一个观察者,并不会改变资源的引用计数

weak_ptr(弱智能指针):它有什么用处,它用来弥补shared_ptr的哪些不足的???

weak_ptr只是一个观察者,并不会改变资源的引用计数,和shared_ptr配合使用,可以解决智能指针的交叉引用问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <string>
#include <memory> //包含C++库里面所有的智能指针
using namespace std;

class B;
class A
{
public:
A(){cout<<"A()"<<endl;}
~A(){cout<<"~A()"<<endl;}
int sum(int a,int b){
return a+b;
}
weak_ptr<B>_ptrb;
};
class B
{
public:
B(){cout<<"B()"<<endl;}
~B(){cout<<"~B()"<<endl;}
int sum(int a,int b){
shared_ptr<A> sp=_ptra.lock(); //弱智能指针的提升方法,weak_ptr=>shared_ptr
if(sp!=nullptr){
//表示资源还在,提升成功
return sp->sum(a,b);
}
else{
throw "a object is released";
}
}
weak_ptr<A>_ptra;//只是一个观察者(观察资源的引用计数),没有提供*运算符重载函数
};
int main()
{
//交叉引用资源泄露
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa->_ptrb=pb;
pb->_ptra=pa;
cout<<pb->sum(1,2)<<endl;
return 0;
}

手写shared_ptr和weak_ptr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <iostream>
#include <string>
#include <unordered_map>
#include <list>
#include <atomic>
using namespace std;

template<typename T>
class Count
{
public:
Count(T *ptr=nullptr):_count(1),_res(ptr){}
//增加资源的引用计数
void add(){
_count++;
}
//减少资源的引用计数
void del(){
_count--;
}
//获取
int get(){
return _count;
}
T* getres(){
return _res;
}
private:
atomic_int _count;//记录资源的引用计数CAS保证引用计数加减的线程安全操作
T *_res;//记录资源地址
};

template<typename T>
class shared_ptr
{
public:
shared_ptr(T *ptr=nullptr):mptr(ptr),mcount(nullptr)
{
//增加资源的引用计数
if(mptr!=nullptr){
mcount=new Count<T>(mptr);
}
}
~shared_ptr()
{
if(mptr!=nullptr){
mcount->del();
if(mcount->get()==0){
delete mptr;
}
}
}
shared_ptr(const shared_ptr<T> &src)
{
mptr=src.mptr;
mcount=src.mcount;
if(mcount!=nullptr){
mcount->add();
}
}
shared_ptr<T>& operator=(const shared_ptr<T> &src)
{
if(this==&src)
return *this;
if(mptr!=nullptr){
mcount->del();
if(mcount->get()==0){
delete mptr;
}
}
mptr=src.mptr;
mcount=src.mcount;
if(mcount!=nullptr){
mcount.add();
}
return *this;
}
T* operator->()
{
return mptr;
}
T& operator*()
{
return *mptr;
}
operator void*(){return mptr;}
private:
T *mptr;//指向资源的裸指针
Count<T> *mcount;
template<typename E>
friend class weak_ptr;
};

template<typename T>
class weak_ptr
{
public:
weak_ptr():mcount(nullptr){}
weak_ptr(const shared_ptr<T> &sp){
mcount=sp.mcount;
}
weak_ptr<T>& operator=(const shared_ptr<T> sp){
mcount=sp.mcount;
return *this;
}
shared_ptr<T> lock(){
if(mcount==nullptr){
return shared_ptr<T>();
}
else{
if(0==mcount->get()){
return shared_ptr<T>();
}
else{
return shared_ptr<T>(mcount->getres());
}
}
}
private:
Count<T> *mcount;//指向资源的裸指针
};

class B;
class A
{
public:
A(){cout<<"A()"<<endl;}
~A(){cout<<"~A()"<<endl;}
int sum(int a,int b){
return a+b;
}
weak_ptr<B>_ptrb;
};
class B
{
public:
B(){cout<<"B()"<<endl;}
~B(){cout<<"~B()"<<endl;}
int sum(int a,int b){
shared_ptr<A> sp=_ptra.lock(); //弱智能指针的提升方法,weak_ptr=>shared_ptr
if(sp!=nullptr){
//表示资源还在,提升成功
return sp->sum(a,b);
}
else{
throw "a object is released";
}
}
weak_ptr<A>_ptra;//只是一个观察者(观察资源的引用计数),没有提供*运算符重载函数
};
int main()
{
//交叉引用资源泄露
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa->_ptrb=pb;
pb->_ptra=pa;
cout<<pb->sum(1,2)<<endl;
return 0;
}