某厂面试,当时反正是没写出来,估计是寄了,事后做个记录。
#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() { // privateif(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;
}
预期输出为: