2016-08-28 3 views
0

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; 
} 
+2

이러한 문제를 해결하는 올바른 도구는 디버거입니다. 스택 오버플로를 묻기 전에 코드를 단계별로 실행해야합니다. 자세한 도움말은 [작은 프로그램 디버깅 방법 (Eric Lippert 작성)] (https://ericlippert.com/2014/03/05/how-to-debug-small-programs/)을 참조하십시오. 문제를 재현하는 [최소, 완료 및 확인 가능] (http://stackoverflow.com/help/mcve) 예제와 함께 해당 질문을 \ [편집]해야합니다. 디버거. –

+1

A4/Letter 종이, 연필 및 지우개를 가져갑니다. 3 요소가있는 이중 연결된 목록을 그립니다. (개체는 사각형이며 포인터는 화살표입니다.) 2 개의 요소가있는 다른 링크 된 목록을 그립니다. 이제'operator ='가하는 것을 추적합니다 (새로운 사각형과 화살표를 그리고 오래된 것을 지움). 이제 둘 다 파괴되면 어떻게 될지 추적하십시오. –

+0

* 규칙 3를 따르고 있습니다 * - 원래 목록과 동일한 데이터를 가지며 두 목록 간의 포인터를 공유하지 않는 ** 새로운 ** 독립형 연결 목록을 만들어야합니다. – PaulMcKenzie

답변

4

당신은 세 가지의 규칙을 "다음"있습니다하지만 당신은 어떤 규칙을 이해하지 about :

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

이 구현은 생성 된 기본 생성자가 수행하는 것입니다. 실제로 요소를 복사해야합니다. 마찬가지로, 당신은 단지 포인터와 복사 및 원본의 소멸자를 복사 할 것입니다 delete 동일한 요소.

+0

감사합니다. 그것은 확실히 의미가 있습니다. 나는 현재 변화를 만들고 있으며 이것이 어떻게 진행되는지보고 싶어합니다. 곧 업데이트를 추가 할 것입니다. – Bidyut

+0

valgrind 문제도 확실히 수정되었습니다. 다시 한 번 감사드립니다! 빠른 질문 : 내 할당 및 추가 연산자 과부하도 변경해야한다는 의미입니까? – Bidyut

+0

@Bidyut : 당신의 임무는 아무 것도하지 않습니다. 실제로 할당하려면 분명히 변경해야합니다! 'swap()'오퍼레이션을 얻었 으면 복사 생성자를 사용할 수 있습니다 :'L & L :: operator = (L tmp) {this-> swap (tmp); return * this; }'.operator +()는 복사 생성자와 같은 문제를 겪습니다. 다시 복사 생성자를 활용할 수 있지만 이번에는'splice()'작업을 통해 복사 생성자를 활용할 수 있습니다. –