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)
, 내 이중 연결리스트의 코드가 될 때 : 다음과 같이
Valgrind의 출력은 (내가 반대 포인터를 자유롭게 아니에요 이해하지만, 내가 얻을 수도 전에 내가 무료로 하나의 방법을 얻을 수 없습니다.) 나는 Rule of Three을 다음있어
#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);
}
. 누군가 내가 왜 이것을 보는지 이해할 수있는 올바른 방향으로 향하게 할 수 있습니까? 나는 많은 다른 구현을 연구하고 시도했지만, 어떤 것은 더 악화되었다. 특히 DLinkedList listB(listA);
이 main()
내부에서 호출 될 때 문제가 발생하는 것 같습니다.
업데이트 : 여러분의 도움 덕분에 문제를 파악할 수있었습니다. 하지만 이제 확장자에서 연산자 오버로드와 비슷한 문제가 발생했습니다. 도와 주셔서 감사합니다. 올바른 방향으로 몇 가지 "포인터"를 고맙게 생각합니다. ,
==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)
만 연산자 오버로드를 게시 생성자를 복사하고 소멸자 : Valgrind의 코드 아래에 게시
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;
}
이러한 문제를 해결하는 올바른 도구는 디버거입니다. 스택 오버플로를 묻기 전에 코드를 단계별로 실행해야합니다. 자세한 도움말은 [작은 프로그램 디버깅 방법 (Eric Lippert 작성)] (https://ericlippert.com/2014/03/05/how-to-debug-small-programs/)을 참조하십시오. 문제를 재현하는 [최소, 완료 및 확인 가능] (http://stackoverflow.com/help/mcve) 예제와 함께 해당 질문을 \ [편집]해야합니다. 디버거. –
A4/Letter 종이, 연필 및 지우개를 가져갑니다. 3 요소가있는 이중 연결된 목록을 그립니다. (개체는 사각형이며 포인터는 화살표입니다.) 2 개의 요소가있는 다른 링크 된 목록을 그립니다. 이제'operator ='가하는 것을 추적합니다 (새로운 사각형과 화살표를 그리고 오래된 것을 지움). 이제 둘 다 파괴되면 어떻게 될지 추적하십시오. –
* 규칙 3를 따르고 있습니다 * - 원래 목록과 동일한 데이터를 가지며 두 목록 간의 포인터를 공유하지 않는 ** 새로운 ** 독립형 연결 목록을 만들어야합니다. – PaulMcKenzie