处理对自定义智能指针的悬空引用

时间:2016-08-12 08:43:41

标签: c++11 pointers smart-pointers

免责声明:是的,我知道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类与上面的代码非常相似。

0 个答案:

没有答案