免责声明:是的,我知道shared_ptr。但我仍然想这样做。 另外,我知道我没有使用锁或原子,所以这不是线程安全的。
假设以下有点简单的“智能”指针实现。语义是,如果你通过值传递,你增加引用计数,如果你坚持引用,你有一个'弱'的种类:
#pragma once
#include <iostream>
#include <cassert>
using std::cout;
template <class T>
class Ptr {
private:
T* ptr;
int* refCount;
public:
Ptr(T* ptr) {
assert(ptr);
this->ptr = ptr;
this->refCount = new int(1);
}
Ptr(Ptr& from) {
swap(*this, from);
}
Ptr(Ptr&& from) {
swap(*this, from, false);
}
Ptr& operator=(const Ptr& from) {
swap(*this, from);
return *this;
}
~Ptr() {
if (*refCount >= 1) {
(*refCount)--;
cout << "\n Ptr destructor: new ref count: " << *refCount;
if (*refCount == 0) {
delete ptr;
ptr = nullptr;
}
}
}
operator bool() {
return (*refCount >= 1);
}
T* operator->() {
assert(*refCount >= 1);
return ptr;
}
int referenceCount() {
return *refCount;
}
private:
template <class T>
void swap(Ptr<T>& to, Ptr<T>& from, bool isCopy = true) {
assert((*from.refCount) >= 1);
to.ptr = from.ptr;
to.refCount = from.refCount;
if (isCopy) {
(*to.refCount)++;
}
else {
from.ptr = nullptr;
}
}
};
class A {
public:
A() = default;
~A() {
cout << "\n dealloc:" << this;
}
void doSomething() {
}
};
void Test() {
{
Ptr<A> p1(new A);
cout << "\ncheckpoint - refCount (should be 1): " << p1.referenceCount();
Ptr<A> p2 = p1;
cout << "\ncheckpoint - refCount (should be 2): " << p1.referenceCount();
Ptr<A>& p3 = p1;
cout << "\ncheckpoint - refCount (should be 2): " << p1.referenceCount();
Ptr<A> p4 = std::move(p1);
cout << "\ncheckpoint - refCount (should be 2): " << p4.referenceCount();
Ptr<A> p5 = p4;
cout << "\ncheckpoint - refCount (should be 3): " << p5.referenceCount();
}
cout << "\nend";
}
我得到以下输出,这是预期的:
checkpoint - refCount (should be 1): 1
checkpoint - refCount (should be 2): 2
checkpoint - refCount (should be 2): 2
checkpoint - refCount (should be 2): 2
checkpoint - refCount (should be 3): 3
Ptr destructor: new ref count: 2
Ptr destructor: new ref count: 1
Ptr destructor: new ref count: 0
dealloc:00C3D060
但是有一个大问题。
假设我保留了任何这些引用(可能是这个问题的指针 - 任何作为弱引用的句柄),并且最后一个强引用超出了范围。原始指针现在为空,智能指针的计数器(我正在泄漏)仍然允许任何弱句柄表现得恰当,因为它仍然保持有效值0。
但是如果我删除了计数器指针,那么任何剩下的引用最终会指向其他数据,如果该内存位置被用于其他内容,可能包括0以外的任何数字。
所以我想我可能需要创建一个值为0的静态指针,而是使用指向计数器的指针?那样,无论哪个强引用删除指针,都可以将所有计数器指向静态0?
我对此感到困惑。特别是因为我正在查看渲染引擎的源代码,他们的共享ptr类与上面的代码非常相似。