【问题标题】:Custom reference counting pointer calls destructor right after creation自定义引用计数指针在创建后立即调用析构函数
【发布时间】:2021-03-30 19:58:44
【问题描述】:

我目前正在阅读 David H. Eberly 的“3D 游戏引擎架构”一书,并决定实现我自己的小引用计数智能指针。我主要关注他的实施,但我的实施遇到了问题。

我创建了一个名为'centereref'的函数,返回指针。当我在与我创建的对象相同的范围内使用此函数时,一切都很好,但是当我将对象置于全局范围内时,它会在创建后立即销毁该对象。

class Object
{
public:
    void IncrementReferences()
    {
        ++m_References;
    }
    void DecrementReferences()
    {
        if(--m_References == 0) delete this;
    }
    int GetReferenceCount() const { return m_References; }

private:
    int m_References = 0;
};
template<class T>
class Pointer
{
public:
    //costr and destr
    Pointer(T* pObject = nullptr)
    {
        m_pObject = pObject;
        if (m_pObject)
            m_pObject->IncrementReferences();
    }

    Pointer(const Pointer& rPointer)
    {
        m_pObject = rPointer.m_pObject;
        if (m_pObject)
            m_pObject->IncrementReferences();
    }

    ~Pointer()
    {
        if (m_pObject)
            m_pObject->DecrementReferences();
    }

    // implicit conversions
    operator T* () const
    {
        return m_pObject;
    }
    T& operator* () const
    {
        return *m_pObject;
    }
    T* operator-> () const
    {
        return m_pObject;
    }

    // Assignment
    Pointer& operator= (T* pObject)
    {
        if (m_pObject != pObject)
        {
            if (pObject)
                pObject->IncrementReferences();

            if (m_pObject)
                m_pObject->DecrementReferences();

            m_pObject = pObject;
        }
        return *this;
    }
    Pointer& operator= (const T* rReference)
    {
        if (m_pObject != rReference)
        {
            if (rReference)
                rReference->IncrementReferences();

            if (m_pObject)
                m_pObject->DecrementReferences();

            m_pObject = rReference;
        }
        return *this;
    }

    // Comparisons
    bool operator== (T* pObject) const { return m_pObject == pObject; }
    bool operator!= (T* pObject) const { return m_pObject != pObject; }
    bool operator== (const Pointer& rReference) const { return m_pObject == rReference.m_pObject; }
    bool operator!= (const Pointer& rReference) const { return m_pObject != rReference.m_pObject; }

protected:
    // The shared object
    T* m_pObject;
};
template<typename T>
using Ref = Pointer<T>;

template<typename T, typename ...Args>
constexpr Ref<T> CreateRef(Args&&... args)
{
    return Ref<T>(new T(args...));
}

主要

static Ref<Person> person = nullptr; // Doesn't work like this

static void DoSomething()
{
    person = CreateRef<Person>("Name");
    std::cout << "References " << person->GetReferenceCount() << std::endl;

    Ref<Person> newPerson = person;
    std::cout << "References " << newPerson->GetReferenceCount() << std::endl;
}

int main()
{
    DoSomething();

    std::cout << person->GetReferenceCount();
}

我感觉我对“指针”类做错了,但我不太明白我缺少什么。

【问题讨论】:

  • 启动你的调试器。将断点放在IncrementReferencesDecrementReferences()方法中。查看断点的位置、this 指针是什么以及它们执行时调用堆栈是什么。如果您不知道如何使用调试器,这是一个愉快的学习时期。使用调试器,完美的问题使得吨更容易。发布您在这里的调试器中收集的信息,我们可以提供帮助。 span>
  • 所以我尝试调试,这就是调用堆栈到达IncrementReferenceDecrementReference 时的样子。这两个都在“DoSomething()”函数的第一行连续调用
  • Pointer类模板需要复制分配。 span>
  • @TsvetelinD Pointer&amp; operator= (const Pointer&amp; rPointer) -- 您的Pointer 类缺少此功能,因此违反了rule of 3

标签: c++ pointers game-engine smart-pointers reference-counting


【解决方案1】:

感谢您的帮助。我找到了两个解决问题的方法。

第一个解决方案是在Pointer 类中添加一个复制赋值运算符。

Pointer& operator= (Pointer& rPointer)
    {
        if (m_pObject != rPointer.m_pObject)
        {
            if (rPointer)
                rPointer.m_pObject->IncrementReferences();

            if (m_pObject)
                m_pObject->DecrementReferences();

            m_pObject = rPointer.m_pObject;
        }
        return *this;
    }

另一个解决方案(虽然不是我想要的)是将CreateRef() 函数的返回类型更改为T*

template<typename T, typename ...Args>
constexpr T* CreateRef(Args&&... args)
{
    return new T(args...);
}

【讨论】:

  • 第一个解决方案是添加另一个复制赋值运算符 -- 在添加上面的代码之前,您没有任何复制赋值运算符。你之前所做的是重载=,但之前的那些函数都不是复制赋值。
  • 感谢您的澄清!在我可以自信地说我在 c++ 方面表现不错之前还有很长的路要走
猜你喜欢
  • 2012-02-10
  • 2014-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-23
  • 2023-02-05
  • 2016-11-05
  • 2016-03-20
相关资源
最近更新 更多