前言
手写一个 shared_ptr
代码
头文件
#ifndef SHARED_PTR_H
#define SHARED_PTR_H
#include <atomic>
#include <utility>
namespace tyz {
template<typename T>
class default_deleter {
public:
void operator()(T* ptr) {
delete ptr;
}
};
template<typename T, typename deleter = default_deleter<T>>
class shared_ptr {
private:
std::atomic_int *user_count = nullptr;
T* ptr = nullptr;
public:
shared_ptr() = default;
shared_ptr(T* );
shared_ptr(const shared_ptr& );
shared_ptr(shared_ptr&& );
shared_ptr& operator=(const shared_ptr &);
shared_ptr& operator=(shared_ptr&& );
~shared_ptr();
void swap(shared_ptr& lhs);
T* get() { return ptr;}
int count() { return *user_count;}
void reset();
T* operator->() { return ptr;}
T& operator*() { return *ptr;}
};
template<typename T, typename deleter>
shared_ptr<T, deleter>::shared_ptr(T* ptr_)
:user_count(new std::atomic_int(1)), ptr(ptr_){
}
template<typename T, typename deleter>
shared_ptr<T, deleter>::shared_ptr(const shared_ptr& lhs) :
ptr(lhs.ptr), user_count(lhs.user_count) {
++*user_count;
}
template<typename T, typename deleter>
shared_ptr<T, deleter>::shared_ptr(shared_ptr&& lhs) {
std::swap(ptr, lhs.ptr);
std::swap(user_count, lhs.user_count);
}
template<typename T, typename deleter>
shared_ptr<T, deleter>& shared_ptr<T, deleter>::operator=(const shared_ptr &lhs) {
shared_ptr temp(lhs);
swap(temp);
return *this;
}
template<typename T, typename deleter>
shared_ptr<T, deleter>& shared_ptr<T, deleter>::operator=(shared_ptr&& lhs) {
if (this != &lhs) {
if (ptr) {
if (--*user_count <= 0) {
deleter()(ptr);
delete user_count;
}
ptr = nullptr;
user_count = nullptr;
}
swap(lhs);
}
return *this;
}
template<typename T, typename deleter>
shared_ptr<T, deleter>::~shared_ptr() {
if (ptr) {
if (--*user_count <= 0) {
deleter()(ptr);
delete user_count;
}
}
}
template<typename T, typename deleter>
void shared_ptr<T, deleter>::swap(shared_ptr& lhs) {
std::swap(ptr, lhs.ptr);
std::swap(user_count, lhs.user_count);
}
template<typename T, typename deleter>
void shared_ptr<T, deleter>::reset() {
if (ptr) {
if (--*user_count <= 0) {
deleter()(ptr);
delete user_count;
}
ptr = nullptr;
user_count = nullptr;
}
}
// when we use shared_ptr, we cann't designate the deleter
template<typename T, typename... Args>
shared_ptr<T> make_shared(Args&&... args) {
return shared_ptr<T>(new T (std::forward<Args>(args)...));
}
}
#endif
测试代码
#include "shared_ptr.h"
#include <iostream>
using std::cout;
using std::endl;
struct Student {
int id;
int age;
Student(int _id, int _age):id(_id), age(_age){}
};
void print(tyz::shared_ptr<Student> &s) {
if (s.get() == nullptr) {
cout << "nullptr" << endl;
return;
}
cout << "id: " << s->id << endl
<< "age: " << s->age << endl;
cout << s.count() << endl;
}
int main() {
//tyz::shared_ptr<Student> test_ptr(new Student(1, 20));
tyz::shared_ptr<Student> test_ptr = tyz::make_shared<Student>(1, 20);
tyz::shared_ptr<Student> test_ptr2 = tyz::make_shared<Student>(1, 20);
tyz::shared_ptr<Student> ptr1 = test_ptr; // copy constructor
print(ptr1);
ptr1 = test_ptr2; // copy assignment
print(test_ptr1);
print(test_ptr2);
tyz::shared_ptr<Student> ptr2(test_ptr); // copy constructor
print(ptr2);
tyz::shared_ptr<Student> ptr3(std::move(test_ptr)); // move constructor
print(ptr3);
print(test_ptr); // should be nullptr
tyz::shared_ptr<Student> ptr4 = std::move(ptr1); // move assignment
print(ptr4);
print(ptr1); // should be nullptr
ptr4.reset();
print(ptr2); // wheather user_count - 1 ?
}
注意事项
- 在写赋值操作符时,请始终记得处理自赋值
- 用 拷贝并交换 写出的拷贝赋值是天生 异常安全并能处理自赋值的
- 写移动函数时,直接置空指针并交换 达到最高效率
- 实际的 shared_ptr 的 user_count 应为一个结构体,里面不只含有引用计数,还有弱引用计数,删除器等
- 智能指针并非多线程安全的,原因在于 这篇文章
- make_shared 中不应加入 deleter 原因:
“如果使用自定义删除器,则在创建智能指针对象时不能使用make_unique或make_shared函数。
这个想法是,如果您需要一种专门的方法来删除对象,那么您可能也需要一种专门的方法来创建它们。” 并且 基于 new 创建 应当基于 delete 销毁,不应该有自定义删除器。