智能指针
智能指针其实就是一个class(类),要让这个类像一个指针,里面一定会有一个指针去模拟指针,指针有 * 和 -> 操作符,对于一个class去模拟point,我们必须对其 * 和 -> 操作符进行重载。
template<typename T>
class shared_prt{
public:
T& operator*() const{
return *px;
}
T* operator->() const{
return px;
}
private:
T* px;
long* pn;
};
// 在调用的时候比如制造一个FOO的智能指针去使用它
struct FOO{
...
void method(){}
};
int main(){
shared_prt<FOO> sp(new FOO);
FOO f(*sp); //
sp->method(); //相当于px->method()
}
1.智能指针的作用
C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理。程序员自己管理堆内存可以提高了程序的效率,但是整体来说堆内存的管理是麻烦的,C++11中引入了智能指针的概念,方便管理堆内存。使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,程序发生异常时内存泄露等问题等,使用智能指针能更好的管理堆内存。
2.智能指针的设计和实现
下面是一个简单智能指针的demo。
智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个指针(这个指针实际指的是类对象)共享同一对象。
-
每次创建类的新对象时,初始化指针并将引用计数置为1;
-
当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;
-
对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;
-
调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。
智能指针就是模拟指针动作的类。所有的智能指针都会重载 -> 和 * 操作符。智能指针还有许多其他功能,比较有用的是自动销毁。这主要是利用栈对象的有限作用域以及临时对象(有限作用域实现)析构函数释放内存。
#include <iostream>
2 #include <memory>
3
4 template<typename T>
5 class SmartPointer {
6 private:
7 T* _ptr;
8 size_t* _count;
9 public:
10 SmartPointer(T* ptr = nullptr) :
11 _ptr(ptr) {
12 if (_ptr) {
13 _count = new size_t(1);
14 } else {
15 _count = new size_t(0);
16 }
17 }
18
19 SmartPointer(const SmartPointer& ptr) {
20 if (this != &ptr) {
21 this->_ptr = ptr._ptr;
22 this->_count = ptr._count;
23 (*this->_count)++;
24 }
25 }
26
27 SmartPointer& operator=(const SmartPointer& ptr) {
28 if (this->_ptr == ptr._ptr) {
29 return *this;
30 }
31
32 if (this->_ptr) {
33 (*this->_count)--;
34 if (this->_count == 0) {
35 delete this->_ptr;
36 delete this->_count;
37 }
38 }
39
40 this->_ptr = ptr._ptr;
41 this->_count = ptr._count;
42 (*this->_count)++;
43 return *this;
44 }
45
46 T& operator*() {
47 assert(this->_ptr == nullptr);
48 return *(this->_ptr);
49
50 }
51
52 T* operator->() {
53 assert(this->_ptr == nullptr);
54 return this->_ptr;
55 }
56
57 ~SmartPointer() {
58 (*this->_count)--;
59 if (*this->_count == 0) {
60 delete this->_ptr;
61 delete this->_count;
62 }
63 }
64
65 size_t use_count(){
66 return *this->_count;
67 }
68 };
69
70 int main() {
71 {
72 SmartPointer<int> sp(new int(10));
73 SmartPointer<int> sp2(sp);
74 SmartPointer<int> sp3(new int(20));
75 sp2 = sp3;
76 std::cout << sp.use_count() << std::endl;
77 std::cout << sp3.use_count() << std::endl;
78 }
79 //delete operator
80 }
参考
c++智能指针——原理与实现
详细介绍了unique_ptr、shared_ptr 和 weak_ptr,并且实现了一个指针
C++智能指针总结
详细介绍了auto_ptr、unique_ptr、shared_ptr 和 weak_ptr,有测试代码,测试了创建释放的过程
C++“智能指针”能自动释放内存?它怎么知道内存是如何分配的?
讲述了shared_ptr默认的是delete,可以自己定义其他的,如delete[] 时定义deleter
C++ 如何避免内存泄漏
讲了几种其他避免内存泄漏的方法,如使用 Arena,使用 Coroutine,善用 RAII等
LevelDB源码剖析之Arena内存管理
浅谈----RAII资源获得即初始化(Resource Acquisition Is Initialization)
RAII 的做法是使用一个对象,在其构造时获取资源,在对象生命期控制对资源的访问使之始终保持有效,最后在对象析构的时候释放资源。
简单来说,RAII 可以帮助我们将管理堆上的内存,简化为管理栈上的内存,从而达到利用编译器自动解决内存回收问题的效果。此外,RAII 可以简化的还不仅仅是内存管理,还可以简化对资源的管理,例如 fd,锁,引用计数等等。
当我们需要在堆上分配内存时,我们可以同时在栈上面分配一个对象,让栈上面的对象对堆上面的对象进行封装,用时通过在栈对象的析构函数中释放堆内存的方式,将栈对象的生命周期和堆内存进行绑定。
unique_ptr 就是一种很典型的例子。然而 unique_ptr 管理的对象类型只能是指针,对于其他的资源,例如 fd,我们可以通过将 fd 封装成另外一个 FileHandle 对象的方式管理,也可以采用一些更通用的方式。例如,在我们内部的 C++ 基础库中实现了 Defer 类,想法类似于 Go 中 defer。
C++ STL 四种智能指针
在最后面分析了应用场景