我有一个类似于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;
};
此类可以包含父级和一组子级。我实施addChild
和setParent
成员函数时遇到问题:
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));
}
}
我期望会发生什么:
Message::addChild
被称为thisPtr
childPtr->parent() != thisPtr
将被解析为true
childPtr->setParent(thisPtr);
,Message::setParent
被执行,thisPtr
引用计数将增加1,因为创建了共享指针的副本。现在thisPtr
的引用次数为2 Message::setParent
被执行时,m_parentPtr = parentPtr;
会将m_parentPtr
,parentPtr
和thisPtr
引用计数增加1;这3个智能指针现在的引用数为3。Message::setParent
并销毁parentPtr
,将m_parentPtr
和thisPtr
的引用次数减少1 Message::addChild
。现在引用计数thisPtr
为2。实际发生的事情:
当执行退出if
Message::addChild
中的thisPtr
语句时,引用计数再次减少1,使thisPtr
的引用计数为1.这会使所有内容都中断执行存在Message::addChild
,thisPtr
被破坏,因此this
被删除。
我的问题:
为什么thisPtr
引用计数会在执行退出if
中的Message::addChild
语句或实际发生的情况时再次减少?...
答案 0 :(得分:2)
- 当
醇>Message::setParent
被执行时,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
的共享指针。