2014-12-23 2 views
-2

데이터 구조 및 알고리즘 과정에 동적 배열 데이터 구조를 구현하려고하는데 메모리 관리에 문제가있는 것 같습니다. 내 템플릿 클래스는 다음과 같습니다.동적 배열 데이터 구조를 구현할 때 "double free or corruption"오류가 발생했습니다.

ArrayList.h

#include <iostream> 
#include <cstring> 
using namespace std; 
#define Length(array) (sizeof((array))/sizeof((array[0]))) 

template <class T> 
class ArrayList 
{ 
    public: 

    ArrayList() {a = new T[1]; n = 0;} 
    ~ArrayList() {delete [] a;} 

    int size(); 
    int backingSize(); 
    T get(int i); 
    T set(int i, T x); 
    void add(int i, T x); 
    T remove (int i); 

    private: 

    void resize(); 

    T *a; 
    int n; 
}; 

template <class T> 
int ArrayList<T>::size() { return n; } 

template <class T> 
int ArrayList<T>::backingSize() { return Length(a); } 

template <class T> 
T ArrayList<T>::get(int i) { return a[i]; } 

template <class T> 
T ArrayList<T>::set(int i, T x) 
{ 
    T temp = a[i]; 
    a[i] = x; 
    return temp; 
} 

template <class T> 
void ArrayList<T>::add(int i, T x) 
{ 
    if (n+1 > Length(a)) resize(); 
    for (int j = n; j > i; j--) a[j] = a[j-1]; 
    a[i] = x; 
    n++; 
} 

template <class T> 
T ArrayList<T>::remove(int i) 
{ 
    T temp = a[i]; 
    for (int j = i; j < n-1; j++) a[j] = a[j+1]; 
    n--; 
    if (Length(a) > 3*n) resize(); 
    return temp; 
} 

template <class T> 
void ArrayList<T>::resize() 
{ 
    if (n+1 > Length(a)) 
    { 
     cout << "Making Bigger\n"; 
     T* tempArr = new T[2*n]; 
     memcpy(tempArr, a, n * sizeof(T)); 
     delete [] a; 
     a = tempArr; 
    } 

    else // (Length(a) > 3*n) 
    { 
     cout << "Making Smaller\n"; 
     T* tempArr = new T[n/2]; 
     memcpy(tempArr, a, n * sizeof(T)); 
     delete [] a; 
     a = tempArr; 
    } 
} 

I는 다음과 같은 주요 기능을 테스트

TestArrayList.cpp 코드는 컴파일하고 다음과 같은 출력으로 실행

#include "ArrayList.h" 
#include <iostream> 

using namespace std; 

int main() 
{ 
    ArrayList <int> myList; 

    cout << myList.size() << "\n\n"; 

    myList.add(0,15); 
    cout << myList.get(0) << ", " << myList.size() << ", " << myList.backingSize() << "\n"; 
    myList.add(1,34); 
    cout << myList.get(1) << ", " << myList.size() << ", " << myList.backingSize() << "\n"; 
    myList.add(2,23); 
    cout << myList.get(2) << ", " << myList.size() << ", " << myList.backingSize() << "\n"; 
    myList.add(3,1); 
    cout << myList.get(3) << ", " << myList.size() << ", " << myList.backingSize() << "\n\n"; 

    myList.~ArrayList(); 
} 

터미널에 :

15, 1, 2 
34, 2, 2 
Making Bigger 
23, 3, 2 
Making Bigger 
1, 4, 2 

*** Error in `./TestArrayList': double free or corruption (fasttop): 0x000000000090c010 *** 
Aborted 

예상대로 작동하는 것처럼 보입니다. get 함수는 인덱스에 적절한 값을 반환하고 size 함수는 적절한 길이의 배열을 반환하며 seg fault는 없습니다. 그러나 backingSize() 함수는 항상 2를 반환하고 잘못된 메모리 관리와 관련이 있다고 가정하는 끝에 던져진 오류가 발생합니다. 나는 꽤 오랫동안 엉망이 되었기 때문에 어떤 도움을 주시면 감사하겠습니다.

+0

또한 타입에 대한 복사 생성자, 할당 연산자 및 이동 대입 연산자를 정의해야합니다 (또는 삭제하십시오) – OMGtechy

+0

디버거를 단계별로 실행하여 'delete []'를 두 번 누르는 위치를 결정할 수 있습니까? –

+2

소멸자를 명시 적으로 호출하지 마십시오. 변수가 범위를 벗어날 때 자동으로 호출됩니다. – grep

답변

4

명시 적으로 개체의 소멸자를 호출하십시오. 소멸자는 자동으로 호출되므로 이미 호출 했으므로 이중 자유 오류가 발생합니다.

은 (어떤 다른 사람이없는 경우 확실하지) 여기에 버그가이 link

0

포인터에는 #define Length(array) (sizeof((array))/sizeof((array[0])))을 사용하지 마십시오. 포인터에서 배열의 크기를 알 수있는 방법은 없습니다. 이것은 아마 당신의 문제로 이어질 것입니다. 클래스가 있기 때문에 크기와 용량을 변수로 저장하지 않는 이유는 무엇입니까? 배열 타입 객체를 다룰 때 크기와 용량이 메모리에서 차지하는 8 바이트는 실제로 아무 것도 아닙니다.

1

에서 봐, 소멸자가 호출 될 때 이해하기 :

T* tempArr = new T[n/2]; // the size is n/2 
memcpy(tempArr, a, n * sizeof(T)); // but here you try to copy n elements 

tempArrn/2 요소를 저장할 수있는, 하지만 당신은 그것에 n 요소를 복사하려고합니다. 정의되지 않은 동작입니다. 또한 모든 가능한 유형에 대해 바이트 단위로 요소를 복사하는 것은 실현 불가능합니다 T.

+0

첫 번째로, 나는 그것이 2 이상의 백킹 어레이의 길이라는 것을 의미했습니다. 감사. 나는 두 번째 부분을 완전히 이해하고 있는지 잘 모르겠습니다. memcpy()를 모든 타입에 사용할 수 없다는 것을 말하고 있습니까? int로 테스트하기 때문에 제 경우에는 작동합니까? – jasper

+0

@jasper'int'는 쉽게 복사 할 수 있기 때문에'int'에서 작동합니다. – kraskevich

관련 문제