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

C++11 处理对自定义智能指针的悬空引用,c++11,pointers,smart-pointers,C++11,Pointers,Smart Pointers,免责声明:是的,我知道共享ptr。但我还是想这么做。 另外,我知道我没有使用锁或原子,因此这不是线程安全的 假设下面是一个“智能”指针的简单实现。语义是,如果通过值传递,则会增加引用计数;如果坚持引用,则会出现“弱”排序: #pragma once #include <iostream> #include <cassert> using std::cout; template <class T> class Ptr { private: T* p

免责声明:是的,我知道共享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";
}
但有一个大问题

假设我保留了这些引用中的任何一个(可能是这个问题的指针——任何充当弱引用的句柄),最后一个强引用超出了范围。原始指针现在为null,并且智能指针的计数器(我正在泄漏)仍然允许任何弱句柄正常工作,因为它仍然保持有效值0

但是,如果我删除了计数器指针,如果该内存位置被用于其他内容,那么剩下的任何引用最终都会指向其他数据,其中可能包括除0以外的任何数字

所以我想我可能需要包装一个指向0值的静态指针,而不是使用指向计数器指针的指针?这样,无论哪个强引用删除指针,都可以将所有计数器指向静态0


我有点困惑。特别是因为我正在查看渲染引擎的源代码,它们的共享ptr类与上面的代码非常相似。

有一个原因是有两个计数器:一个用于数据,另一个用于数据。即使您不想使用std::shared_ptr(为什么?),您也可能会发现它很有用。我将查看实现说明,谢谢!但从你的评论来看,我开始认为应该保留两个计数器,即使强指针计数器变为0,也不应该删除refCounter,直到所有“观察者”真正消失,不管是弱还是强?关于我不想使用shared_ptr的原因:因为这是一个3d渲染器,我觉得shared_ptr就像stl中的很多东西都是臃肿的,如果它不需要适应所有可能的用例,性能可能会更高。有一个原因是有两个计数器:一个用于数据,一个用于数据。即使您不想使用std::shared_ptr(为什么?),您也可能会发现它很有用。我将查看实现说明,谢谢!但从你的评论来看,我开始认为应该保留两个计数器,即使强指针计数器变为0,也不应该删除refCounter,直到所有“观察者”真正消失,不管是弱还是强?关于我不想使用shared_ptr的原因:因为这是针对3d渲染器的,我觉得shared_ptr就像stl中的很多东西都很臃肿,如果它不需要适应所有可能的用例,那么性能可能会更好。
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