s

sansuitaibai

V1

2022/11/17阅读:23主题:默认主题

简单实现shared_ptr

12. 智能指针的简单实现

设想:

  • 如下代码: 我们不能简单通过只设置一个static int count 的变量来作用动态内存的引用计数的量,因为这样就是每个相同类型的模板类都拥有该变量,并不是指向同一块的动态内存的引用指针拥有同一个引用引用计数量。
  • 我们实现的目的是对一块动态内存引用的计数,通过上面实现我们知道设置一个静态的变量是实现不通。又有一个想法就是设置一个普通类型计数变量,但是此时引用同一块内存的计数就是不统一的,只是属于各自的变量
  • 因此我们需要单独开辟一个内存来保存引用计数,这样只要对同一块内存的引用发生改变了,我们就可以修改这个动态分配的引用计数的值,这个动态分配的内存是唯一的,指向相同动态内存的智能指针内存保存一个指针类型指向该引用变量的内存即可。
#include<iostream>
using namespace std;

template<typename T>
class A {
public:
 A() {
  newmem = nullptr;
  cout << "现有use_count: " << use_count << endl;

 }
 A(T arg) {
  ++use_count;
  cout << "现有use_count: " << use_count << endl;
  newmem = new T(std::move(arg));
 }
 ~A() {
  if (newmem != nullptr) {
   --use_count;
  }
  if (use_count == 0) {
   delete newmem;
  }
  cout << "剩余use_count: " << use_count << endl;
 }
 T* newmem;
 static int use_count;
};

template<typename T>
int A<T>::use_count = 0;

int main() {

 A<int> p1;
 A<intp2(99);
 {
  A<intp3(100);
 }
 A<const char*> p4("akfjd");


 return 0;
}
image-20221117212045720
image-20221117212045720

方法

  • 引用计数,就是在内存中开辟一块内存专门用于存储资源被引用的次数,自己保留一个指向计数器的指针,计数器初始化为 1。每次用已有的 shared_ptr 构造新的 shared_ptr 或者给已有的 shared_ptr 赋值时,通过指针将计数器加 1,所有指向同一个资源的 shared_ptr 也指向同一个计数器。

  • shared_ptr 析构或主动释放所有权时,应将引用计数减 1,然后判断引用计数是否归零,如果归零,那么就释放指针指向的内存,此后将计数器指针置为空。需要注意的是,如果将计数器指针置为空,为了防止指针主动释放所有权之后计数器指针为空,导致判断计数是否归零,需要在判断计数归零前先判断计数指针是否为空。

shared_ptr的简单实现

#include<iostream>
#include<string>
using namespace std;

#define EXIT_NULL(s){ \
  std::cout << s << std::endl; \
  exit(EXIT_FAILURE);\
 }


template<typename T>
class Shared_ptr{
private:
 T* _ptr;//指向分配的对象的内存
 int* pcount; //记录该_ptr指向对象有多少个引用
public:
 Shared_ptr():_ptr(nullptr),pcount(nullptr) {
  cout << "进入默认构造函数" << endl;
  cout << "退出默认构造函数" << endl;
 }
 Shared_ptr(T* pr) :_ptr(pr), pcount(new int(1)) {
  cout << "进入有参构造函数" << endl;
  cout << "退出有参构造函数" << endl;
 }
 Shared_ptr(const Shared_ptr<T>& rh) :_ptr(rh._ptr), pcount(rh.pcount) {
  cout << "进入拷贝构造函数" << endl;
  if (pcount != nullptr) {
   ++(*pcount);
  }
  cout << "退出拷贝构造函数" << endl;
 }
 ~Shared_ptr() {
  cout << "进入析构函数" << endl;
  if (this->pcount) {
   this->release();
  }
  cout << "进入析构函数" << endl;

 }
 bool operator==(const Shared_ptr<T>& rh) {
  return this->_ptr == rh._ptr ? true : false;
 }
 Shared_ptr<T>& operator=(const Shared_ptr<T>& rh) {
  cout << "进入拷贝赋值函数" << endl;
  if (*this == rh)
   return *this;
  
  this->release();
  this->_ptr = rh._ptr;
  this->pcount = rh.pcount;
  if (this->pcount != nullptr) {
   ++(*this->pcount);
  }
  cout << "退出拷贝赋值函数" << endl;
  
 }

public:
 void release() {
  
  if (pcount != nullptr && --(*pcount) == 0) {
   delete this->pcount;
   this->pcount = nullptr;
   delete _ptr;
   
  }
  this->_ptr = nullptr;
  this->pcount = nullptr;
  
 }
 bool unique() {
  return this->use_count() == 1 ? true : false;
 }
 int use_count() {
  if (this->pcount) {
   return *this->pcount;
  }
  return 0;
 }
 
 T* get() {
  return this->_ptr;
 }
 T& operator*() {
  if (this->_ptr == nullptr) {
   EXIT_NULL("pointer is nullptr\n");
  }
  return *(this->_ptr);
 }
 T* operator->() {
  if (this->_ptr == nullptr) {
   EXIT_NULL("pointer is nullptr\n");
  }
  return this->_ptr;
 }
};


int main() {

 Shared_ptr<std::stringp1(new std::string("Hello world!"));
 std::cout << "p1.get()" << p1.get() << std::endl;
 std::cout << "p1.use_count() "<< p1.use_count() << std::endl;
 Shared_ptr<std::stringp2(p1);
 std::cout << "p2.get()" << p2.get() << std::endl;
 std::cout << "p2.use_count() " << p2.use_count() << std::endl;
 Shared_ptr<std::string> p3;
 p3 = p2;
 std::cout << "p3.get()" << p3.get() << std::endl;
 std::cout << "p3.use_count() " << p3.use_count() << std::endl;
 
 p2.release();
 std::cout << "p2.use_count() " << p2.use_count() << std::endl;
 std::cout << "p1.get()" << p1.get() << std::endl;
 std::cout << "p1.use_count() " << p1.use_count() << std::endl;
 //std::cout << *(p2.get()) << std::endl;
 std::cout << "*p1" << *p1 << std::endl;
 std::cout << "*p3" << *p3 << std::endl;
 std::cout << "p1->size() " << p1->size() << std::endl;
 std::cout << "*p2" << *p2 << std::endl;

 return 0;


 return 0;
}
image-20221117224406908
image-20221117224406908

分类:

后端

标签:

C++

作者介绍

s
sansuitaibai
V1