这个指针和 QSharedPointer
this pointer and QSharedPointer
我有一个类似 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;
};
这个 class 可以有一个父项和一组子项。我在实现 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
创建时引用计数为 1
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
- 执行 returns 到
Message::addChild
。现在 thisPtr
的引用计数是 2.
实际发生了什么:
当执行退出 Message::addChild
中的 if
语句时 thisPtr
引用计数再次减 1,留下 thisPtr
的引用计数为 1。这使一切都崩溃了当执行存在时 Message::addChild
,thisPtr
被销毁,因此 this
被删除。
我的问题:
为什么 thisPtr
引用计数在执行退出 Message::addChild
中的 if
语句时再次减少,或者那里实际发生了什么?...
下面是它在调试器中的运行方式:
- As
Message::setParent
gets executed, m_parentPtr = parentPtr;
will increase m_parentPtr
, parentPtr
and thus thisPtr
reference counts by 1; these 3 smart pointers now have a reference count of 3.
5.1。然后,setParent
构造一个指向 child 的临时共享指针,引用计数为 1 并在 parent 上调用 addChild
:
m_parentPtr->addChild(Message::Ptr(this));
5.2。 addChild
创建一个指向 parent 的共享指针,引用计数为 1:
Message::Ptr thisPtr(this);
5.3。 addChild
returns,破坏了 5.2 的那个共享指针,它破坏了 parent,它破坏了 parent 的 QSet<Message::Ptr> m_children
成员。
5.4。 5.1的临时共享指针被销毁,即销毁child.
更一般地说,你有一个循环引用:parents拥有children,而children拥有他们的parents,这是记忆的秘诀泄漏和 use-after-delete 错误。构造新的共享指针拥有其他共享指针已经拥有的原始指针是 double-delete 和 use-after-delete 错误的秘诀;共享指针不会相互了解,它们的引用计数将独立变化。您应该调查 QWeakPointer
to break the cycle and QEnableSharedFromThis
以安全地获取指向 *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;
};
这个 class 可以有一个父项和一组子项。我在实现 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
创建时引用计数为 1childPtr->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 - 执行 returns 到
Message::addChild
。现在thisPtr
的引用计数是 2.
实际发生了什么:
当执行退出 Message::addChild
中的 if
语句时 thisPtr
引用计数再次减 1,留下 thisPtr
的引用计数为 1。这使一切都崩溃了当执行存在时 Message::addChild
,thisPtr
被销毁,因此 this
被删除。
我的问题:
为什么 thisPtr
引用计数在执行退出 Message::addChild
中的 if
语句时再次减少,或者那里实际发生了什么?...
下面是它在调试器中的运行方式:
- As
Message::setParent
gets executed,m_parentPtr = parentPtr;
will increasem_parentPtr
,parentPtr
and thusthisPtr
reference counts by 1; these 3 smart pointers now have a reference count of 3.
5.1。然后,setParent
构造一个指向 child 的临时共享指针,引用计数为 1 并在 parent 上调用 addChild
:
m_parentPtr->addChild(Message::Ptr(this));
5.2。 addChild
创建一个指向 parent 的共享指针,引用计数为 1:
Message::Ptr thisPtr(this);
5.3。 addChild
returns,破坏了 5.2 的那个共享指针,它破坏了 parent,它破坏了 parent 的 QSet<Message::Ptr> m_children
成员。
5.4。 5.1的临时共享指针被销毁,即销毁child.
更一般地说,你有一个循环引用:parents拥有children,而children拥有他们的parents,这是记忆的秘诀泄漏和 use-after-delete 错误。构造新的共享指针拥有其他共享指针已经拥有的原始指针是 double-delete 和 use-after-delete 错误的秘诀;共享指针不会相互了解,它们的引用计数将独立变化。您应该调查 QWeakPointer
to break the cycle and QEnableSharedFromThis
以安全地获取指向 *this
.