C++基于模板实现智能指针
某厂面试,当时反正是没写出来,估计是寄了,事后做个记录。
#include <iostream>
#include <mutex>
using namespace std;
class ObjectElement {
private:
char *addr;
int size;
void release() {
addr = nullptr;
size = 0;
}
public:
ObjectElement(int size) {
cout<< "construct: "<<this<<endl;
this->size = size;
addr = new char[size];
}
~ObjectElement() {
cout<< "release: "<<this<<endl;
delete []addr;
release();
}
void PrintTest() {
cout<<"ObjectElement"<<endl;
}
};
// 注意不是线程安全的,需要加锁
template <typename T>
class SharedPtr {
private:
// 可以用一个额外的ControlBlock 结构存储以下两个私有变量,此处只需要一个指针,做不做两可
T *ptr;
int *ref_count; // 核心,如果直接用int:每个shared_ptr 就会有自己的引用计数器,它们不会同步更新
void release() { // private
if(ref_count != nullptr && --(*ref_count) == 0) {
delete ptr;
delete ref_count;
}
}
public:
SharedPtr() : ptr(nullptr), ref_count(nullptr) {}
explicit SharedPtr(T *p) {
ptr = p;
ref_count = new int(1);
}
// 注意只有在拷贝或者赋值的时候才会有引用计数的增加
// 拷贝构造,增加引用计数
SharedPtr(const SharedPtr &s) noexcept {
ptr = s.ptr;
ref_count = s.ref_count;
if(ref_count != nullptr) {
(*ref_count)++;
}
}
// 移动构造,没有增加引用计数
SharedPtr(SharedPtr &&s) noexcept {
ptr = s.ptr;
ref_count = s.ref_count;
s.ptr = nullptr;
s.ref_count = nullptr;
}
// 拷贝赋值运算符,与拷贝构造类似,但是需要先判断是否是自己,注意返回自身引用
SharedPtr& operator=(const SharedPtr &s) noexcept{
if(this == &s) {
release(); // 重要!删除原有的
ptr = s.ptr;
ref_count = s.ref_count;
if(ref_count != nullptr) {
(*ref_count)++;
}
}
return *this;
}
// 移动赋值运算符,同理
SharedPtr& operator=(SharedPtr &&s) noexcept{
if(this == &s) {
release(); // 重要!删除原有的
ptr = s.ptr;
ref_count = s.ref_count;
s.ptr = nullptr;
s.ref_count = nullptr;
}
return *this;
}
// 解引用,重载*,返回T对象
T& operator*() const {
return *ptr;
}
// 重载指针操作符,使得可以类似->调用
T* operator->() const{
return ptr;
}
// 获取裸指针,同上
T* get() const{
return ptr;
}
int use_count() const {
return (ref_count!=nullptr?(*ref_count):0);
}
void reset(T* p = nullptr) {
release();
ptr = p;
if(p == nullptr) {
ref_count = nullptr;
}
else {
ref_count = new int(1);
}
}
~SharedPtr() {
release();
}
};
int main() {
ObjectElement *obj = new ObjectElement(100);
SharedPtr<ObjectElement> sptr1(obj);
SharedPtr<ObjectElement> sptr2 = sptr1;
cout<<sptr1.use_count()<<endl;
cout<<sptr2.use_count()<<endl;
(*sptr1).PrintTest();
sptr1->PrintTest();
sptr1.get()->PrintTest();
sptr1.reset();
cout<<sptr1.use_count()<<endl;
cout<<sptr2.use_count()<<endl;
return 0;
}
预期输出为: