简体   繁体   English

这个指针和 QSharedPointer

[英]this pointer and QSharedPointer

I have a tree-node like class called Message which looks like this:我有一个类似 class 的树节点,名为Message ,如下所示:

class Message
{
public:
    using Ptr = QSharedPointer<Message>;

public:
    explicit Message();
    explicit Message(Message::Ptr parentPtr);
    explicit Message(const Data &data, Message::Ptr parentPtr = Message::Ptr());

    void setParent(Message::Ptr parentPtr);
    Message::Ptr parent() const;
    bool hasParent() const;

    QSet<Message::Ptr> children() const;
    void setChildren(const QSet<Message::Ptr> &children);
    bool hasChildren() const;

    Data data() const;
    void setData(const Data &data);

private:
    void addChild(Message::Ptr childPtr);
    void removeChild(Message::Ptr childPtr);

private:
    Message::Ptr m_parentPtr;
    QSet<Message::Ptr> m_children;
    Data m_data;
};

This class can have a parent and a set of children.这个 class 可以有一个父母和一组孩子。 I have a problem when I implemented the addChild and setParent member functions:我在实现addChildsetParent成员函数时遇到问题:

void Message::addChild(Message::Ptr childPtr)
{
    if (!m_children.contains(childPtr)) {
        m_children.insert(childPtr);
    }

    Message::Ptr thisPtr(this);

    if (childPtr->parent() != thisPtr) {
        childPtr->setParent(thisPtr);
    }
}

void Message::setParent(Message::Ptr parentPtr)
{
    if (m_parentPtr != parentPtr) {
        m_parentPtr = parentPtr;

        m_parentPtr->addChild(Message::Ptr(this));
    }
}

What I expect will happen:我期望会发生的事情:

  1. Message::addChild gets called Message::addChild被调用
  2. thisPtr gets created with a reference count of 1 thisPtr创建时引用计数为 1
  3. childPtr->parent() != thisPtr will be resolved to true childPtr->parent() != thisPtr将被解析为true
  4. childPtr->setParent(thisPtr); , Message::setParent gets executed and thisPtr reference count will increase by 1 as a copy of the shared pointer is created. , Message::setParent被执行并且thisPtr引用计数将随着创建共享指针的副本而增加 1。 Now thisPtr has a reference count of 2现在thisPtr的引用计数为 2
  5. As Message::setParent gets executed, m_parentPtr = parentPtr;Message::setParent被执行时, m_parentPtr = parentPtr; will increase m_parentPtr , parentPtr and thus thisPtr reference counts by 1;会将m_parentPtrparentPtrthisPtr引用计数增加 1; these 3 smart pointers now have a reference count of 3.这 3 个智能指针现在的引用计数为 3。
  6. Execution exits Message::setParent and destroy parentPtr decreasing the reference count of m_parentPtr and thisPtr by 1执行退出Message::setParent并销毁parentPtrm_parentPtrthisPtr的引用计数减 1
  7. Execution returns to Message::addChild .执行返回到Message::addChild Now reference count of thisPtr is 2.现在thisPtr的引用计数是 2。

What actually happens:实际发生了什么:

When execution exits the if statement in Message::addChild thisPtr reference count decreases again by 1, leaving thisPtr with a reference count of 1. This makes everything break as when execution exists Message::addChild , thisPtr gets destroyed, thus this deleted.当执行退出Message::addChild中的if语句时, thisPtr引用计数再次减少 1,使thisPtr的引用计数为 1。这使得一切都中断,因为当执行存在Message::addChild时, thisPtr被销毁,因此this被删除。

My question:我的问题:

Why does thisPtr reference count decreases again by when execution exits the if statement in Message::addChild or what actually happens there?...为什么thisPtr引用计数会在执行退出Message::addChild中的if语句或那里实际发生的情况时再次减少?...

Here is how it runs in the debugger:以下是它在调试器中的运行方式: 在此处输入图像描述

  1. As Message::setParent gets executed, m_parentPtr = parentPtr; Message::setParent被执行时, m_parentPtr = parentPtr; will increase m_parentPtr , parentPtr and thus thisPtr reference counts by 1; 将增加m_parentPtrparentPtr ,因此thisPtr引用计数增加1; these 3 smart pointers now have a reference count of 3. 这3个智能指针现在的引用计数为3。

5.1. 5.1。 Then, setParent constructs a temporary shared pointer to the child with reference count 1 and calls addChild on the parent: 然后, setParent构造一个指向引用计数为1的子级的临时共享指针,并在父级上调用addChild

m_parentPtr->addChild(Message::Ptr(this));

5.2. 5.2。 addChild creates a shared pointer to the parent with reference count 1 : addChild创建一个指向引用计数为1的父级的共享指针:

Message::Ptr thisPtr(this);

5.3. 5.3。 addChild returns, destroying that shared pointer of 5.2, which destroys the parent, which destroys the parent's QSet<Message::Ptr> m_children member. addChild返回,破坏了5.2的共享指针,破坏了父节点,这破坏了父节点的QSet<Message::Ptr> m_children成员。

5.4. 5.4。 The temporary shared pointer of 5.1 is destroyed, which destroys the child. 5.1的临时共享指针被破坏,这将破坏子代。

More generally, you have a cyclic reference: parents own children, and children own their parents, which is a recipe for memory leaks and use-after-delete bugs. 一般来说,您有一个循环引用:父母拥有孩子,而孩子拥有父母,这是内存泄漏和删除后使用错误的秘诀。 Constructing new shared pointers owning raw pointers already owned by other shared pointers is a recipe for double-delete and use-after-delete bugs; 构造拥有其他共享指针已经拥有的原始指针的新共享指针是双重删除和使用后删除错误的诀窍。 the shared pointers won't know about each other, their reference counts will vary independently. 共享的指针不会相互了解,它们的引用计数将独立变化。 You should investigate QWeakPointer to break the cycle and QEnableSharedFromThis to safely obtain a shared pointer to *this . 您应该研究QWeakPointer来打破循环,并研究QEnableSharedFromThis以安全地获取指向*this的共享指针。

See The QEnableSharedFromThis in the Qt documentation.请参阅Qt文档中的 QEnableSharedFromThis。 This should solve your issue.这应该可以解决您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM