用法
#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;
int main(void)
{
// two shared pointers representing two persons by their name
shared_ptr<string> pNico(new string("nico"));
// 自定义析构函数,只是为了展示,实际情况使用默认的就可以了
shared_ptr<string> pJutta(new string("jutta"),
// deleter (a lambda function)
[](string *p)
{
cout << "delete " << *p << endl;
delete p;
}
);
// 获得指向对象(*pNico)
// capitalize person names
(*pNico)[0] = 'N';
// ->调用类String的函数replace
pJutta->replace(0, 1, "J");
// put them multiple times in a container
vector<shared_ptr<string> > whoMadeCoffee;
whoMadeCoffee.push_back(pJutta);
whoMadeCoffee.push_back(pJutta);
whoMadeCoffee.push_back(pNico);
whoMadeCoffee.push_back(pJutta);
whoMadeCoffee.push_back(pNico);
// print all elements
for (auto ptr : whoMadeCoffee)
cout << *ptr << " ";
cout << endl;
// overwrite a name again
*pNico = "Nicolai";
// print all elements
for (auto ptr : whoMadeCoffee)
cout << *ptr << " ";
cout << endl;
// print some internal data
cout << "use_count: " << whoMadeCoffee[0].use_count() << endl;
return 0;
}
结果:
Jutta Jutta Nico Jutta Nico
Jutta Jutta Nicolai Jutta Nicolai
use_count: 4
delete Jutta
分析:
1. 对智能指针pNico的拷贝是浅拷贝,所以当我们改变对象“Nico”的值为“Nicolai”时,指向它的指针都会指向新值。
2. 指向对象“Jutta”的有四个指针:pJutta和pJutta的三份被安插到容器内的拷贝,所以上述程序输出的use_count为4。
3. shared_ptr本身提供默认内存释放器(default deleter),调用的是delete,不过只对“由new建立起来的单一对象”起作用。当然我们也可以自己定义内存释放器,就如上述程序。不过值得注意的是,默认内存释放器并不能释放数组内存空间,而是要我们自己提供内存释放器,如:
shared_ptr<int> p(new int[10], default_delete<int[]>());
或者
shared_ptr<int> pJutta2(new int[10],
// deleter (a lambda function)
[](int *p)
{
delete[] p;
}
);
很好的资料
http://www.cnblogs.com/lanxuezaipiao/p/4132096.html
实现
#include <iostream>
using namespace std;
template<class T>
class SharedPtr {
public:
SharedPtr(T *p);
~SharedPtr();
// 拷贝构造函数
SharedPtr(const SharedPtr<T> &orig);
// =重载
SharedPtr<T>& operator=(const SharedPtr<T> &rhs);
private:
T *ptr;
int *use_count;
};
template<class T>
SharedPtr<T>::SharedPtr(T *p) : ptr(p) {
try {
assert(p!=nullptr);
use_count = new int(1);
}
catch (...) {
if(p==nullptr)
cout<<"Init with nullptr"<<endl;
else {
delete ptr;
use_count = nullptr;
cout<<"Allocate memory for use_count fails."<<endl;
}
exit(1);
}
cout<<"Constructor is called!"<<endl;
}
template<class T>
SharedPtr<T>::~SharedPtr() {
// 只在最后一个对象引用ptr时才释放内存
if(--(*use_count) == 0) {
delete ptr;
delete use_count;
cout<<"Destructor is called!"<<endl;
}
}
template<class T>
SharedPtr<T>::SharedPtr(const SharedPtr<T> &orig) {
ptr = orig.ptr;
// 这里显示出为什么用int *use_count
use_count = orig.use_count;
++(*use_count);
cout<<"Copy constructor is called!"<<endl;
}
// 重载运算为什么返回引用
// https://www.cnblogs.com/codingmengmeng/p/5871254.html
template<class T>
SharedPtr<T>& SharedPtr<T>::operator=(const SharedPtr<T> &rhs) {
// 防止自身赋值而导致提早释放内存
++(*rhs.use_count);
// 将左操作数对象的使用计数减1,若该对象的使用计数减至0,则删除该对象
if(--(*use_count)==0) {
delete ptr;
delete use_count;
}
ptr = rhs.ptr;
use_count = rhs.use_count;
cout<<"Assignment operator overloaded is called!"<<endl;
return *this;
}