我的内存泄漏是由循环引用引起的吗?
Are my memory leaks caused by circular referencing?
我正在用 C++ 创建双向链表。添加到列表前面时,我收到以下 内存泄漏 :
Detected memory leaks!
Dumping objects ->
{193} normal block at 0x000001F7A1EC01B0, 16 bytes long.
Data: < 0 > A0 30 EB A1 F7 01 00 00 00 00 00 00 00 00 00 00
{192} normal block at 0x000001F7A1EB3090, 96 bytes long.
Data: < [J > D0 5B 4A AE F7 7F 00 00 02 00 00 00 01 00 00 00
{149} normal block at 0x000001F7A1EBF9E0, 16 bytes long.
Data: < # > D8 F7 15 23 E4 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.
这是我的代码:
struct Node {
bool exists = false;
int element;
shared_ptr<node> prevNode = nullptr;
shared_ptr<node> nextNode = nullptr;
};
class DLL {
public:
shared_ptr<Node> frontNode = make_shared<Node>();
shared_ptr<Node> backNode = make_shared<Node>();
void frontAdd(int x);
}
void DLL::frontAdd(int x) {
shared_ptr<Node> tempNode = make_shared<Node>();
tempNode->exists = true;
tempNode->element = x;
tempNode->prevNode = nullptr;
if (frontNode->exists) {
tempNode->nextNode = frontNode;
frontNode->prevNode = tempNode;
}
else {
backNode = tempNode;
}
frontNode = tempNode;
};
我尝试过使用唯一指针和弱指针,但我不熟悉弱指针,作为初学者,我发现很难将它们与这个项目集成。
我尝试删除 frontNode 和 tempNode 上的 make_shared,而不是在没有 make_shared 的情况下创建它们,但在这两种情况下,这 returns 写访问冲突说 "returned nullptr"。在 autos 中,tempNode 是空的,所以这是有道理的。
由于 shared_ptr 超出范围,我预计所有所有权都会丢失并且内存泄漏不存在,但我猜是因为 "make_shared" 它被添加到堆中并且所以不能那么容易地从内存中删除?
很可能是您的循环引用造成的。 shared_ptr 不是那么聪明,只是计算引用的数量,后向指针使计数保持非零。
您需要使用原始指针或 weak_ptr<> 来处理任何可以被视为 "back" 指针的内容,无论是来自从属子对象,还是您拥有双向列表的地方.
weak_ptr<>
有操作成本,但优点是子对象可以安全地运行,只需很少的编码工作。
是的,您对所有节点都有循环依赖。每个节点指向下一个和前一个,因此每个节点的多个循环依赖项,在头部和尾部之外。
例如,您可以通过对之前的 link 使用 weak_ptr
来解决此问题。这将导致一些性能损失,因为您需要从弱指针获取新的共享指针以访问先前的节点。
我正在用 C++ 创建双向链表。添加到列表前面时,我收到以下 内存泄漏 :
Detected memory leaks!
Dumping objects ->
{193} normal block at 0x000001F7A1EC01B0, 16 bytes long.
Data: < 0 > A0 30 EB A1 F7 01 00 00 00 00 00 00 00 00 00 00
{192} normal block at 0x000001F7A1EB3090, 96 bytes long.
Data: < [J > D0 5B 4A AE F7 7F 00 00 02 00 00 00 01 00 00 00
{149} normal block at 0x000001F7A1EBF9E0, 16 bytes long.
Data: < # > D8 F7 15 23 E4 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.
这是我的代码:
struct Node {
bool exists = false;
int element;
shared_ptr<node> prevNode = nullptr;
shared_ptr<node> nextNode = nullptr;
};
class DLL {
public:
shared_ptr<Node> frontNode = make_shared<Node>();
shared_ptr<Node> backNode = make_shared<Node>();
void frontAdd(int x);
}
void DLL::frontAdd(int x) {
shared_ptr<Node> tempNode = make_shared<Node>();
tempNode->exists = true;
tempNode->element = x;
tempNode->prevNode = nullptr;
if (frontNode->exists) {
tempNode->nextNode = frontNode;
frontNode->prevNode = tempNode;
}
else {
backNode = tempNode;
}
frontNode = tempNode;
};
我尝试过使用唯一指针和弱指针,但我不熟悉弱指针,作为初学者,我发现很难将它们与这个项目集成。 我尝试删除 frontNode 和 tempNode 上的 make_shared,而不是在没有 make_shared 的情况下创建它们,但在这两种情况下,这 returns 写访问冲突说 "returned nullptr"。在 autos 中,tempNode 是空的,所以这是有道理的。
由于 shared_ptr 超出范围,我预计所有所有权都会丢失并且内存泄漏不存在,但我猜是因为 "make_shared" 它被添加到堆中并且所以不能那么容易地从内存中删除?
很可能是您的循环引用造成的。 shared_ptr 不是那么聪明,只是计算引用的数量,后向指针使计数保持非零。
您需要使用原始指针或 weak_ptr<> 来处理任何可以被视为 "back" 指针的内容,无论是来自从属子对象,还是您拥有双向列表的地方.
weak_ptr<>
有操作成本,但优点是子对象可以安全地运行,只需很少的编码工作。
是的,您对所有节点都有循环依赖。每个节点指向下一个和前一个,因此每个节点的多个循环依赖项,在头部和尾部之外。
例如,您可以通过对之前的 link 使用 weak_ptr
来解决此问题。这将导致一些性能损失,因为您需要从弱指针获取新的共享指针以访问先前的节点。