1. 程式人生 > >C++11--智慧指標詳解及實現

C++11--智慧指標詳解及實現

1、基礎概念

智慧指標的一種通用實現技術是使用引用計數。智慧指標類將一個計數器與智慧指標指向的物件相關聯,用來記錄有多少個智慧指標指向相同的物件,並在恰當的時候釋放物件

每次建立類的新物件時,初始化指標並將引用計數置為1;當物件作為另一物件的副本而建立時,引用計數加1;對一個物件進行賦值時,賦值操作符減少左運算元所指物件的引用計數(如果引用計數為減至0,則刪除物件),並增加右運算元所指物件的引用計數;呼叫解構函式時,建構函式減少引用計數(如果引用計數減至0,則刪除基礎物件)。

下圖是shared_ptr的記憶體模型:

由圖中可以看到,實際上引用計數、自定義銷燬等都不是直接儲存在shared_ptr中,而是通過一個指標指向的一個控制塊儲存的,控制塊是動態分配的記憶體 。

下面是用類模板簡單實現shared_ptr.

#include <iostream>
using namespace std;

template<typename T>
class SmartPointer {
private:
	T* p_;
	size_t* count_;
public:
	SmartPointer(T* ptr = nullptr) : p_(ptr) {
		if (p_) {
			count_ = new size_t(1);
		}
		else {
			count_ = new size_t(0);
		}
	}

	SmartPointer(const SmartPointer& ptr) {
		p_ = ptr.p_;
		count_ = ptr.count_;
		(*count_)++;
	}

	SmartPointer& operator=(const SmartPointer& ptr) {
		if (p_ == ptr.p_) {
			return *this;
		}

		if (p_) {
			if (--(*count_) == 0) {
				delete p_;
				delete count_;
			}
		}

		p_ = ptr.p_;
		count_ = ptr.count_;
		(*count_)++;
		return *this;
	}

	~SmartPointer() {
		if (--(*count_) == 0) {
			delete p_;
			delete count_;
		}
	}

	size_t use_count() {
		return *count_;
	}
};

int main() {
	SmartPointer<int> sp1(new int(10));
	SmartPointer<int> sp2(sp1);
	SmartPointer<int> sp3(new int(20));
	sp2 = sp3;
	std::cout << sp1.use_count() << std::endl;
	std::cout << sp3.use_count() << std::endl;
}

2、智慧指標帶來的效能影響

1)shared_ptr的尺寸是裸指標的兩倍。 

2)會帶來控制塊的開銷。

3)引用計數的遞增和遞減是原子操作,原子操作一般都比非原子操作慢。

3、使用weak_ptr解決shared_ptr的迴圈引用。

 解決方案:將類A,B中的shared_prt改為weak_ptr即可,weak_ptr不會增加shared_ptr的引用計數

class B;
class A {
public:
   weak_ptr<B> p;
   //shared_ptr<B> p;
};
class B {
public:
   weak_ptr<A> p;
   //shared_ptr<A> p;
};
int main() {
  while (true) {
     shared_ptr<A> pa(new A());
     shared_ptr<B> pb(new B());
      pa->p = pb;
      pb->p = pa;
   }
  return 0;
}

參考文章:

1. https://www.cnblogs.com/wxquare/p/4759020.html

2. https://segmentfault.com/a/1190000006860811