某廠面試,當時反正是沒寫出來,估計是寄了,事後做個記錄。
#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;
}
預期輸出為: