gpt4 book ai didi

c++ - 如何使用析构函数清除链表内存,而不会出现 valgrind 错误? [更新 : Operator Overload help]

转载 作者:行者123 更新时间:2023-11-27 22:49:15 24 4
gpt4 key购买 nike

我正在尝试通过 valgrind 调试我的代码,我看到了 invalid free() 问题。看来我的 frees 比我的 allocs 多。

valgrind 输出如下:

==11814== Memcheck, a memory error detector
==11814== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==11814== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==11814== Command: ./doublyLinkedList -v --leak-check=full
==11814==
==11814== Invalid read of size 8
==11814== at 0x400A7A: DLinkedList::~DLinkedList() (doublyLinkedList.cpp:92)
==11814== by 0x400DD1: main (doublyLinkedList.cpp:175)
==11814== Address 0x5a87c88 is 8 bytes inside a block of size 24 free'd
==11814== at 0x4C2B1C6: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11814== by 0x400A90: DLinkedList::~DLinkedList() (doublyLinkedList.cpp:93)
==11814== by 0x400DC5: main (doublyLinkedList.cpp:178)
==11814== Block was alloc'd at
==11814== at 0x4C2A0FC: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11814== by 0x4009B5: DLinkedList::DLinkedList(int) (doublyLinkedList.cpp:57)
==11814== by 0x400D90: main (doublyLinkedList.cpp:175)
==11814==
==11814== Invalid free() / delete / delete[] / realloc()
==11814== at 0x4C2B1C6: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11814== by 0x400A90: DLinkedList::~DLinkedList() (doublyLinkedList.cpp:93)
==11814== by 0x400DD1: main (doublyLinkedList.cpp:175)
==11814== Address 0x5a87c80 is 0 bytes inside a block of size 24 free'd
==11814== at 0x4C2B1C6: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11814== by 0x400A90: DLinkedList::~DLinkedList() (doublyLinkedList.cpp:93)
==11814== by 0x400DC5: main (doublyLinkedList.cpp:178)
==11814== Block was alloc'd at
==11814== at 0x4C2A0FC: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11814== by 0x4009B5: DLinkedList::DLinkedList(int) (doublyLinkedList.cpp:57)
==11814== by 0x400D90: main (doublyLinkedList.cpp:175)
==11814==
==11814==
==11814== HEAP SUMMARY:
==11814== in use at exit: 72,704 bytes in 1 blocks
==11814== total heap usage: 3 allocs, 4 frees, 72,752 bytes allocated
==11814==
==11814== LEAK SUMMARY:
==11814== definitely lost: 0 bytes in 0 blocks
==11814== indirectly lost: 0 bytes in 0 blocks
==11814== possibly lost: 0 bytes in 0 blocks
==11814== still reachable: 72,704 bytes in 1 blocks
==11814== suppressed: 0 bytes in 0 blocks
==11814== Rerun with --leak-check=full to see details of leaked memory
==11814==
==11814== For counts of detected and suppressed errors, rerun with: -v
==11814== ERROR SUMMARY: 4 errors from 2 contexts (suppressed: 0 from 0)

供引用,我的双向链表代码如下:(我知道我没有释放反向指针,但即使在我开始之前,我似乎也无法释放单向指针。)

#include <iostream>

class Node {
friend class DLinkedList;
private:
Node *_pPrev;
Node *_pNext;
int _data;

public:
Node(): _pPrev(nullptr), _pNext(nullptr) { }
Node(int d): _data(d), _pPrev(nullptr), _pNext(nullptr) { }
Node(int d, Node *p, Node *n): _data(d), _pPrev(p), _pNext(n) { }

// Getters
const int getData() {
return _data;
}

const Node* getPreviousNode() {
return _pPrev;
}

const Node* getNextNode() {
return _pNext;
}
};

class DLinkedList {
private:
Node *_pHead;
Node *_pTail;

public:
DLinkedList();
DLinkedList(int d);
DLinkedList(Node *n);
DLinkedList(const DLinkedList &dLList); // Copy Constructor
~DLinkedList(); // Destructor

const DLinkedList operator+(const DLinkedList &dLList) const;
DLinkedList& operator=(const DLinkedList &dLList); // Assignment operator overload

void listDisplay();
void reverseListDisplay();
void append(int d);
void append(Node *n);
void append(const DLinkedList &dLList);
};

DLinkedList::DLinkedList() {
_pHead = _pTail = nullptr;
}

DLinkedList::DLinkedList(int d) {
_pHead = new Node(d, nullptr, nullptr);
_pTail = _pHead;
}

DLinkedList::DLinkedList(Node *n) {
_pHead = n;
_pTail = _pHead;
}

DLinkedList::DLinkedList(const DLinkedList &dLList) {
_pHead = dLList._pHead;
_pTail = dLList._pTail;
}

DLinkedList& DLinkedList::operator=(const DLinkedList &dLList) {
return *this;
}

DLinkedList::~DLinkedList() {
while (Node *currentHead = _pHead) {
Node *next = currentHead->_pNext;
_pHead = currentHead->_pNext;
delete currentHead;
}
}

const DLinkedList DLinkedList::operator+(const DLinkedList &dLList) const {
DLinkedList temp(*this);

temp._pTail->_pNext = dLList._pHead;
temp._pTail->_pNext->_pPrev = temp._pTail;
temp._pTail = dLList._pTail;

return temp;
}

void DLinkedList::listDisplay() {
if (_pHead == nullptr) {
std::cout << "List is empty!" << std::endl;
return;
}

Node *it = _pHead;
while (it != nullptr) {
std::cout << it->_data << std::endl;
it = it->_pNext;
}
std::cout << std::endl;
}

void DLinkedList::reverseListDisplay() {
if (_pHead == nullptr) {
std::cout << "List is empty!" << std::endl;
return;
}

Node *it = _pTail;
while (it != nullptr) {
std::cout << it->_data << std::endl;
it = it->_pPrev;
}
std::cout << std::endl;
}

void DLinkedList::append(int d) {
if (_pHead == nullptr) {
_pHead = new Node(d, nullptr, nullptr);
_pTail = _pHead;
return;
}

Node *n = new Node(d, _pTail, nullptr);
_pTail->_pNext = n;
_pTail = _pTail->_pNext;
}

void DLinkedList::append(Node *n) {
if (_pHead == nullptr) {
_pHead = n;
_pTail = _pHead;
return;
}

_pTail->_pNext = n;
_pTail->_pNext->_pPrev = _pTail;
_pTail = _pTail->_pNext;
}

void DLinkedList::append(const DLinkedList &dLList) {
_pTail->_pNext = dLList._pHead;
_pTail->_pNext->_pPrev = _pTail;
_pTail = dLList._pTail;
}

int main() {
DLinkedList listA(10);
listA.append(20);

DLinkedList listB(listA);
}

我正在关注 Rule of Three .有人可以指出正确的方向来理解为什么我会看到这个吗?我已经研究并尝试了许多不同的实现,但有些只会破坏它更糟。具体来说,当在 main() 中调用 DLinkedList listB(listA); 时,问题似乎出现了。

更新:感谢你们的帮助,我能够找出问题所在。但是现在,在扩展中,我遇到了与运算符重载类似的问题。谢谢你帮我。希望在正确的方向上得到一些“指示”。 Valgrind 和代码如下:

==30270== Memcheck, a memory error detector
==30270== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==30270== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==30270== Command: ./doublyLinkedList
==30270==
10
20
30

30
20
10

10
20
30
10
20
30

==30270== Invalid read of size 8
==30270== at 0x400C31: DLinkedList::~DLinkedList() (doublyLinkedList.cpp:119)
==30270== by 0x400F83: main (doublyLinkedList.cpp:189)
==30270== Address 0x5a87da8 is 8 bytes inside a block of size 24 free'd
==30270== at 0x4C2B1C6: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30270== by 0x400C47: DLinkedList::~DLinkedList() (doublyLinkedList.cpp:120)
==30270== by 0x400F77: main (doublyLinkedList.cpp:193)
==30270== Block was alloc'd at
==30270== at 0x4C2A0FC: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30270== by 0x400A57: DLinkedList::DLinkedList(DLinkedList const&) (doublyLinkedList.cpp:73)
==30270== by 0x400F2B: main (doublyLinkedList.cpp:189)
==30270==
==30270== Invalid free() / delete / delete[] / realloc()
==30270== at 0x4C2B1C6: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30270== by 0x400C47: DLinkedList::~DLinkedList() (doublyLinkedList.cpp:120)
==30270== by 0x400F83: main (doublyLinkedList.cpp:189)
==30270== Address 0x5a87da0 is 0 bytes inside a block of size 24 free'd
==30270== at 0x4C2B1C6: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30270== by 0x400C47: DLinkedList::~DLinkedList() (doublyLinkedList.cpp:120)
==30270== by 0x400F77: main (doublyLinkedList.cpp:193)
==30270== Block was alloc'd at
==30270== at 0x4C2A0FC: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30270== by 0x400A57: DLinkedList::DLinkedList(DLinkedList const&) (doublyLinkedList.cpp:73)
==30270== by 0x400F2B: main (doublyLinkedList.cpp:189)
==30270==
==30270==
==30270== HEAP SUMMARY:
==30270== in use at exit: 72,704 bytes in 1 blocks
==30270== total heap usage: 11 allocs, 13 frees, 73,944 bytes allocated
==30270==
==30270== LEAK SUMMARY:
==30270== definitely lost: 0 bytes in 0 blocks
==30270== indirectly lost: 0 bytes in 0 blocks
==30270== possibly lost: 0 bytes in 0 blocks
==30270== still reachable: 72,704 bytes in 1 blocks
==30270== suppressed: 0 bytes in 0 blocks
==30270== Rerun with --leak-check=full to see details of leaked memory
==30270==
==30270== For counts of detected and suppressed errors, rerun with: -v
==30270== ERROR SUMMARY: 6 errors from 2 contexts (suppressed: 0 from 0)

仅发布运算符重载、复制构造函数和析构函数:

DLinkedList::DLinkedList(const DLinkedList &dLList){

Node *n1 = nullptr; // Current
Node *n2 = nullptr; // Next

if (dLList.pHead_ == nullptr) {
pHead_ = nullptr;
} else {
pHead_ = new Node();
pHead_->data_ = dLList.pHead_->data_;

n1 = pHead_;
n2 = dLList.pHead_->pNext_;
}

while (n2) {
Node *prev = n1;
n1->pNext_ = new Node();
n1 = n1->pNext_;
n1->pPrev_ = prev;
n1->data_ = n2->data_;

n2 = n2->pNext_;
}

pTail_ = n1;
n1->pNext_ = nullptr;
}

DLinkedList& DLinkedList::operator=(const DLinkedList &dLList) {
DLinkedList temp(dLList);
std::swap(temp.pHead_, pHead_);
return *this;
}

DLinkedList& DLinkedList::operator+=(const DLinkedList &dLList) {
(*this).pTail_->pNext_ = dLList.pHead_;
(*this).pTail_->pNext_->pPrev_ = (*this).pTail_;
(*this).pTail_ = dLList.pTail_;
return *this;
}

const DLinkedList DLinkedList::operator+(const DLinkedList &dLList) const {
DLinkedList temp = *this;

temp += dLList;
return temp;
}

DLinkedList::~DLinkedList() {

Node *currentHead = pHead_;
Node *currentTail = pTail_;
while (Node *currentHead = pHead_) {
pHead_ = currentHead->pNext_;
delete currentHead;
}
pHead_ = nullptr;
pTail_ = nullptr;
}

最佳答案

您正在“遵循”三则规则,但您根本不了解规则的内容:

DLinkedList::DLinkedList(const DLinkedList &dLList) {
_pHead = dLList._pHead;
_pTail = dLList._pTail;
}

此实现是生成的默认构造函数将执行的操作。您需要实际复制 元素。实际上,您只需复制指针,拷贝和原始指针的析构函数将删除相同的元素。

关于c++ - 如何使用析构函数清除链表内存,而不会出现 valgrind 错误? [更新 : Operator Overload help],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39194948/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com