首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这个指针和QSharedPointer

这个指针和QSharedPointer
EN

Stack Overflow用户
提问于 2017-01-24 19:58:50
回答 1查看 1.2K关注 0票数 2

我有一个类似于树节点的类,名为Message,如下所示:

代码语言:javascript
复制
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;
};

这个类可以有一个父类和一组子类。当我实现addChildsetParent成员函数时,遇到了一个问题:

代码语言:javascript
复制
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));
    }
}

我期望会发生的事情:

  1. Message::addChild被调用
  2. 创建thisPtr时引用计数为1。
  3. childPtr->parent() != thisPtr将被解析为true
  4. childPtr->setParent(thisPtr);Message::setParent被执行,并且在创建共享指针的副本时,thisPtr引用计数将增加1。现在,thisPtr的引用计数为2。
  5. 在执行Message::setParent时,m_parentPtr = parentPtr;将使m_parentPtrparentPtrthisPtr引用计数增加1;这3个智能指针现在的引用计数为3。
  6. 执行退出Message::setParent并销毁parentPtr,将m_parentPtrthisPtr的引用计数降低1。
  7. 执行返回到Message::addChild。现在thisPtr的参考计数是2。

实际发生了什么:

当执行退出时,Message::addChild thisPtr引用计数中的thisPtr语句再次减少1,而thisPtr的引用计数为1。这使得一切都中断,因为当执行存在Message::addChild时,thisPtr会被销毁,因此this被删除。

我的问题:

为什么当执行退出thisPtr中的if语句或实际发生了什么时,Message::addChild引用计数会再次减少?

以下是它在调试器中的运行方式:

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-01-24 20:31:03

  1. 在执行Message::setParent时,m_parentPtr = parentPtr;将使m_parentPtrparentPtrthisPtr引用计数增加1;这3个智能指针现在的引用计数为3。

5.1。然后,setParent使用引用计数1构造一个指向子的临时共享指针,并在父节点上调用addChild

代码语言:javascript
复制
m_parentPtr->addChild(Message::Ptr(this));

5.2。addChild使用引用计数1创建一个指向父的共享指针。

代码语言:javascript
复制
Message::Ptr thisPtr(this);

5.3。addChild返回,销毁该共享指针5.2,该指针破坏父节点,并破坏父节点的QSet<Message::Ptr> m_children成员。

5.4。临时共享指针5.1被销毁,这将破坏子节点。

更普遍的情况是,您有一个循环引用:父母拥有子女,子女拥有他们的父母,这是内存泄漏和删除后使用bug的配方。构造拥有其他共享指针已经拥有的原始指针的新共享指针是一种双重删除和使用后删除错误的方法;共享指针将彼此不知道,它们的引用计数将独立变化。您应该研究QWeakPointer以打破循环,并研究QEnableSharedFromThis以安全地获得指向*this的共享指针。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41837870

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档