更安全的进行资源管理
概念
- 存在
<memory>
头文件中。
- RAII(Resource Acquisition Is Initialization):是通过借助一个对象的声明周期来控制资源的一种技术。
std::auto_ptr(C++98,慎用)
std::unique_ptr(C++11)
**std::make_unique
**:
- 用于创建
std::unique_ptr
它简化了 std::unique_ptr
的创建,并提供了与之类似的性能优势。
- 例如:
auto ptr = std::make_unique<MyStruct>(10, 3.14);
- 需要注意的是,
std::make_unique
是 C++14 引入的,在 C++11 中不可用。
std::shared_ptr(C++11)
template <class T> class shared_ptr;
- 支持拷贝赋值和允许拷贝赋值运算符。
- 但是存在循环引用问题。
- 共享所有权,适用于多个指针需要共享同一个对象的场景。
**std::allocate_shared
和std::make_shared
**:
std::make_shared
是一个用于创建 std::shared_ptr 智能指针的便利函数。
与 std::make_shared
类似,但std::allocate_shared
允许使用自定义的分配器来分配内存。
例如: std::shared_ptr<MyStruct> ptr = std::allocate_shared<MyStruct>(my_allocator, 10, 3.14);
操作
使用get()获取原始指针:当需要传递智能指针管理的对象给只接受原始指针的函数时,可以使用get()成员函数。
使用reset()重置智能指针:reset()函数用于改变智能指针所指向的对象。如果智能指针是唯一指向该对象的指针,则原对象会被释放。否则,引用计数会减一。
使用use_count()
成员函数来获取当前shared_ptr
的引用计数。
使用unique()
成员函数来检查shared_ptr
是否唯一指向其对象(即引用计数为1)。
简单使用
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
| #include <iostream> #include <memory> using namespace std;
template <class T> struct FreeFunc { void operator()(T *ptr) { cout << "free:" << ptr << endl; free(ptr); } }; template <class T> struct DeleteArrayFunc { void operator()(T *ptr) { cout << "delete[]" << ptr << endl; delete[] ptr; } }; int main() { FreeFunc<int> freeFunc; std::shared_ptr<int> sp1((int *)malloc(4), freeFunc); DeleteArrayFunc<int> deleteArrayFunc; std::shared_ptr<int> sp2((int *)malloc(4), deleteArrayFunc);
std::shared_ptr<FILE> sp5(fopen("test.txt", "w"), [](FILE *p) { fclose(p); });
return 0; }
|
循环引用问题
例如两个shared_ptr
对象通过两个指针prev
,next
相互连接,它们相互为对方提供一个引用计数
,导致双方的引用计数始终不为0,从而导致循环引用。
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 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
| #include <iostream> #include <utility> #include <string>
using namespace std;
template <class T> class SmartPtr { public: explicit SmartPtr(T *ptr) : _ptr(ptr), _counter(new int(1)) { }
~SmartPtr() { if (--*(_counter) == 0) { cout << "free" << endl; delete _ptr; delete _counter; } }
SmartPtr(const SmartPtr<T> &smartPtr) : _ptr(smartPtr._ptr), _counter(smartPtr._counter) { cout << "拷贝构造"<<endl; ++(*_counter); }
SmartPtr<T> &operator=(SmartPtr &other) { if (_ptr != other._ptr) { if (--*(_counter) == 0) { cout << "赋值拷贝中的清0" << endl; delete _ptr; delete _counter; } cout << "赋值拷贝" << endl; _counter = other._counter; _ptr = other._ptr; ++(*_counter); } return *this; }
T *input_ptr() { return _ptr; } T *output_ptr() { return _ptr; } T &operator*() { return *_ptr; } T *&operator->() { return _ptr; }
private: T *_ptr; int *_counter; };
int main() { SmartPtr smartPtr_pair(new pair<string, string>("first", "second")); SmartPtr smartPtr_int(new int(5));
SmartPtr smartPtr_str1(new string("abcd")); SmartPtr smartPtr_str2(smartPtr_str1);
SmartPtr smartPtr_double1(new double(3.14)); SmartPtr smartPtr_double2(new double(3.15)); smartPtr_double1 = smartPtr_double2;
cout << smartPtr_pair->first << " " << smartPtr_pair->second << endl; cout << *smartPtr_int << endl;
return 0; }
|
std::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
| #include <iostream> #include <memory> #include <vector>
class Node { public: std::shared_ptr<Node> next; std::weak_ptr<Node> prev;
Node() { std::cout << "Node created\n"; } ~Node() { std::cout << "Node destroyed\n"; } };
int main() { std::shared_ptr<Node> first = std::make_shared<Node>(); std::shared_ptr<Node> second = std::make_shared<Node>();
first->next = second; second->prev = first;
std::cout << "first use count: " << first.use_count() << std::endl; std::cout << "second use count: " << second.use_count() << std::endl;
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
| #include <iostream> #include <utility> #include <string> #include <functional>
using namespace std;
template <class T> class SmartPtr { public: template <class D> SmartPtr(T *ptr,D del) : _ptr(ptr), _counter(new int(1)), _del(del) { } ~SmartPtr() { if (--*(_counter) == 0) { cout << "free" << endl; _del(_ptr); delete _counter; } }
private: T *_ptr; int *_counter; function<void(T*)> _del; };
int main() {
SmartPtr<string> smartPtr_str(new string("abcd"),[](string* ptr){delete(ptr);cout<<"资源管理器";});
return 0; }
|