2017-01-24 186 views
1

我有这样一类树节点称为Message,看起来像这样:this指针QSharedPointer

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成员函数:

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;将增加1 m_parentPtrparentPtr因此thisPtr引用计数;这些3个智能指针现在有3
  6. 执行的引用计数退出Message::setParent和破坏parentPtr由1
  7. 执行返回递减的m_parentPtrthisPtr引用计数Message::addChild。现在参考thisPtr数为2

实际发生的:

当执行1退出在Message::addChildthisPtr引用计数if声明再次降低,留下thisPtr与1这是一个引用计数当执行存在时会使所有内容破坏Message::addChild,thisPtr被破坏,因此this被删除。

我的问题:

为什么thisPtr引用计数通过在执行退出在Message::addChildif陈述或实际发生的情况有再次下降...

下面是如何在调试器中运行? : enter image description here

+2

你不能只将'* this'的所有权移交给'QSharedPointer'(你甚至可以多次执行)。阅读[文档](http://doc.qt.io/qt-5/qsharedpointer.html#QSharedPointer-1)。 – molbdnilo

+0

哇,这是一个恼人的动画 - 你不能把它放到文本形式吗? –

+0

@JesperJuhl嗯,这正是我在7点上做的*我期望会发生什么* ... –

回答

2
  • 作为Message::setParent GET被执行,m_parentPtr = parentPtr;将增加m_parentPtr,parentPtr并因此thisPtr引用计数减1;这3个智能指针现在的引用计数为3.
  • 5.1。然后,setParent构建临时共享指向该子参考计数1和父调用addChild

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

    5.2。 addChild创建一个共享指针到母体参考计数1

    Message::Ptr thisPtr(this); 
    

    5.3。 addChild返回,破坏5.2的共享指针,这会破坏父级的成员,从而破坏父级的QSet<Message::Ptr> m_children成员。

    5.4。 5.1的临时共享指针被销毁,这会破坏孩子。

    更一般地说,你有一个循环引用:父母自己的孩子,孩子拥有他们的父母,这是内存泄漏和使用后删除错误的秘诀。构建拥有已被其他共享指针拥有的原始指针的新共享指针是双删除和后删除后使用错误的秘诀;共享指针不会彼此了解,它们的引用计数将独立变化。您应该调查QWeakPointer以中断周期,并调用QEnableSharedFromThis以安全地获取指向*this的共享指针。