智能指针剖析(shared_ptr实现)

为什么需要智能指针

防止new的时候忘记进行delete,出现异常时,不会执行delete,造成内存泄露。所以诞生了智能指针。
防止内存泄漏,毕竟资源即对象。

  1. 泛型指针
    (1) 指void*指针,可以指向任意数据类型,因此具有“泛型”含义。
    (2) 指具有指针特性的泛型数据结构,包含泛型的迭代器、智能指针等。
    广义的迭代器是一种不透明指针,能够实现遍历访问操作。通常所说的迭代器是指狭义的迭代器,即基于C++的STL中基于泛型的iterator_traits实现的类的实例。泛型指针和迭代器是两个不同的概念,其中的交集则是通常提到的迭代器类。
  2. 原生指针(Raw Pointer)就是普通指针,与它相对的是使用起来行为上象指针,但却不是指针。说“原生”是指“最简朴最基本的那一种”。因为现在很多东西都抽象化理论化了,
  3. 智能指针(Smart Pointer)是C++里面的概念:由于 C++ 语言没有自动内存回收机制,程序员每次得自己处理内存相关问题,但用智能指针便可以有效缓解这类问题。引入智能指针可以防止出现悬垂指针的情况。

1、shared_ptr

shared_ptr(共享指针)
允许多个指针指向同一个对象;
管理指针的存储,提供有限的垃圾收集功能,并可能与其他对象共享该管理。shared_ptr类型的对象具有获取指针所有权并共享该所有权的能力:一旦获得所有权,则指针的所有者组在它们的最后一个释放该所有权时对其删除负责。shared_ptr对象在销毁它们本身或通过赋值操作或显式调用shared_ptr :: reset更改其值后立即释放它们共同拥有的对象的所有权。

shared_ptr的使用

#include 
using namespace std;
int main()
{
       
   shared_ptr<string> p1;
    if(!p1)                     
        cout<<"p1==NULL"<<endl;
        
  shared_ptr<string> p2(new string); 
  if(p2&&p2->empty()){
              
    *p2="helloworld"; 
    cout<<*p2<<endl;
  }

//    shared_ptr pa = new int(1);//!error:不允许以暴露裸漏的指针进行赋值操作。
    shared_ptr<string> pint(new string("normal usage!"));
    cout<<*pint<<endl;
    
    //推荐的安全的初始化方式
    shared_ptr<string> pstr = make_shared<string>("safe uage!");
    cout<<*pstr<<endl;
    //通常使用auto来简单的保存make_shared
    auto  autoptr = make_shared<vector<string>>();
    auto  autoptr = make_shared<string>("123");
	cout << *autoptr << endl;
}

2、shared_ptr的拷贝赋值

接受指针参数的只能指针构造函数是explicit的,因此,我们不能将一个内置指针隐式转化为一个只能指针,必须使用直接初始化形式

//错误! 不会进行隐式转换,类型不符合
shared_ptr<int> p = new int(111);
//正确,直接初始化调用构造函数
shared_ptr<int> p(new int(111);

每个 shared_ptr 都有一个关联的计数值,通常称为引用计数。无论何时我们拷贝一个 shared_ptr,计数器都会递增。
例如,当用一个 shared_ptr 初始化另一个 shred_ptr,或将它当做参数传递给一个函数以及作为函数的返回值时,它所关联的计数器就会递增。当我们给 shared_ptr 赋予一个新值或是 shared_ptr 被销毁(例如一个局部的 shared_ptr 离开其作用域)时,计数器就会递减。一旦一个 shared_ptr 的计数器变为0,它就会自动释放自己所管理的对象。 ------《C++ primer》
//

auto r = make_shared<int>(11);
r= q;//r被释放

这里我的记法是左减右加,r只有创建的时候被计数器引用一次,之后被一次复制导致自减,所以r所指向的int被释放。

shared_ptrの析构函数

shared_ptr(); Destroy shared_ptr
Destroys the object. But, before, it may produce the following side effects depending on the value of member use_count:
If use_count is greater than 1 (i.e., the object is sharing ownership of its managed object with other shared_ptr objects): The use count of the other objects with which it shares ownership is decreased by 1.
If use_count is 1 (i.e., the object is the unique owner of the managed pointer): the object pointed by its owned pointer is deleted (if the shared_ptr object was constructed with a specefic deleter, this is called; Otherwise, the function uses operator delete).
If use_count is zero (i.e., the object is empty), this destructor has no side effects.

销毁对象。但是,根据成员use_count的值,它可能会产生以下副作用:
如果use_count大于1(即,对象与其他shared_ptr对象共享其托管对象的所有权):与该对象共享所有权的其他对象的使用计数减少1。
如果use_count是1(即,对象是唯一的管理指针的所有者):指向的对象通过其拥有的指针被删除(如果shared_ptr的对象用specefic构造删除器,这就是所谓的;否则,该函数使用操作者删除)。
如果use_count为零(即对象为空),则此析构函数没有副作用。

说的都不是人话,意思就是如果计数器大于1,则计数器自减,如果等于1 则直接用指针删除
如果等于0 没有用。
shared_ptr自动销毁对象并自动释放相关的内存

// shared_ptr destructor example
#include 
#include 
int main () {
     
  auto deleter = [](int*p){
     
    std::cout << "[deleter called]\n"; delete p;
  };
  std::shared_ptr<int> foo (new int,deleter);
  std::cout << "use_count: " << foo.use_count() << '\n';
  return 0;                        // [deleter called]
}

智能指针的实现


#include 
#include 

using namespace std;

template<typename T>
class SharedPtr {
     
public:
	SharedPtr() : _ptr((T*)0), _refCount(0) {
     }

	SharedPtr(T* obj) : _ptr(obj), _refCount(new int(1))
	{
     
		cout << "create object : " << *_ptr << "\trefCount = 1" << endl;
	}

	SharedPtr(SharedPtr& other) : _ptr(other._ptr), _refCount(&(++* other._refCount))
	{
     
		cout << "copy constructor : " << *_ptr << "\trefCount = " << *_refCount << endl;
	}

	~SharedPtr()
	{
     
		if (_ptr && -- * _refCount == 0) {
     
			cout << *_ptr << "\trefCount = 0. delete the _ptr:" << *_ptr << endl;
			delete _ptr;
			delete _refCount;
		}
	}

	SharedPtr& operator=(SharedPtr& other)
	{
     
		if (this == &other)
			return *this;

		++* other._refCount;
		if (-- * _refCount == 0) {
     
			cout << "in function operator = . delete " << *_ptr << endl;
			delete _ptr;
			delete _refCount;
		}

		_ptr = other._ptr;
		_refCount = other._refCount;
		cout << "in function operator = . " << *_ptr << "\t_refCount = " << *_refCount << endl;
		return *this;
	}

	T* operator->()
	{
     
		if (_refCount == 0)
			return 0;

		return _ptr;
	}

	T& operator*()
	{
     
		if (_refCount == 0)
			return (T*)0;

		return *_ptr;
	}

private:
	T* _ptr;
	int* _refCount;     //should be int*, rather than int
};


int main()
{
     
	SharedPtr<string> pstr(new string("ptr1"));
	SharedPtr<string> pstr2(pstr);
	SharedPtr<string> pstr3(new string("ptr3"));
	pstr3 = pstr2;
	return 0;
}

为什么多线程读写 shared_ptr 要加锁

看了看陈硕的帖子,大致就是一点,因为智能指针毕竟是个指针类嘛,这个类有俩成员变量,一个是指针,另一个是引用计数器,进行读写的时候如果不加锁,被别的线程用了咋办 = =,俩线程各读一个,这不就内容干扰了吗?没了。有些人就是这样,不爱说大白话,非扯一些套话,跟美国人的书似的,好多人都说,哇,看英文原版一看就看懂了,不废话吗?写的多清楚啊,都啰嗦了。bb叨叨的,单词认识的我都头疼。

你可能感兴趣的:(C++)