智能指针

C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用

简介

智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。C++ 11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。该引用计数的内存在堆上分配。当新增一个时引用计数加1,当过期时引用计数减一。只有引用计数为0时,智能指针才会自动释放引用的内存资源。对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针,因为一个是指针,一个是类。可以通过make_shared函数或者通过构造函数传入普通指针。并可以通过get函数获得普通指针。

为什么要使用智能指针

智能指针的作用是管理一个指针,因为存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏。使用智能指针可以很大程度上的避免这个问题,因为智能指针是一个类,当超出了类的实例对象的作用域时,会自动调用对象的析构函数,析构函数会自动释放资源。所以智能指针的作用就是在函数结束时自动释放内存空间,不需要手动释放内存空间

unique_ptr

unique_ptr实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。它对于避免资源泄露(例如“以new创建对象后因为发生异常而忘记调用delete”)特别有用。

因此,unique_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
class Entity{
public:
Entity(){
cout<<"construct Entity"<<endl;
}
~Entity(){
cout<<"析构函数 "<<endl;
}
};


auto test(unique_ptr<Entity> uptr){
cout<<"test funtion begin!"<<endl;
{ //tmp = uptr(error,不允许copy)
unique_ptr<Entity> tmp = std::move(uptr);
uptr = std::move(tmp);
}
return uptr;//不建议使用return std::move(uptr);冗余使用
}

int main(int argc, const char *argv[]) {
cout<<"main funtion begin!"<<endl;
auto uptr = make_unique<Entity>();//构造unique_ptr
auto res = test(std::move(uptr));//移交使用权时必须用move
cout<<"main will end!"<<endl;
return 0;
}

shared_ptr

shared_ptr实现共享式拥有概念。多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。从名字share就可以看出了资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。可以通过成员函数use_count()来查看资源的所有者个数。除了可以通过new来构造,还可以通过传入auto_ptr, unique_ptr,weak_ptr来构造。当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放

成员函数:

use_count 返回引用计数的个数(long)

unique 返回是否是独占所有权( use_count 为 1 //true or false)

swap 交换两个 shared_ptr 对象(即交换所拥有的对象)

reset 放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少

get 返回内部对象(指针), 由于已经重载了()方法, 因此和直接使用对象是一样的

手写smartPointer

sharepointer

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
#include <iostream>
#include <vector>

template <class T>
class SharePointer{
private:
class Implement{
public:
T * _ptr;
size_t _count;
Implement(T* p):_ptr(p),_count(1){}
~Implement(){
delete _ptr;
}
};
Implement * mImplement;
public:
SharePointer(T* p):mImplement(new Implement(p)){}

~SharePointer(){
decrease();
}
SharePointer(const SharePointer& other):mImplement(other.mImplement){
increase();//拷贝引用计数++
}
SharePointer& operator =(const SharePointer& other){
if(mImplement != other.mImplement){
decrease();
mImplement = other.mImplement;
increase();
}
return this;
}
T* operator ->()const{
return mImplement->_ptr;
}
T& operator *()const{
return *(mImplement->_ptr);
}
size_t use_count(){
return mImplement->_count;
}
private:
void decrease(){
if(!mImplement->_count)delete mImplement;
else mImplement->_count--;
}
void increase(){
mImplement->_count++;
}
};

class test {
public:
test(int value) { this->a = value; }
test(const test& p) { this->a = p.a; }
int a = 20;
void print() { std::cout << "a = " << a << std::endl; }
};

int main(int argc, const char* argv[]) {
SharePointer<test> p = new test(20);
std::cout<<p.use_count()<<std::endl;
{
SharePointer<test>t = p;
std::cout<<p.use_count()<<std::endl;
p->print();
}
std::cout<<p.use_count()<<std::endl;
return 0;
}