2009-08-06 11 views
1

그래서이 두 번째 동적 배열은 내가 끝낼 때 해제하려는 내용입니다. 그러나 나는 소멸자 뒤에 힙 손상으로 계속 달리고있다. 소멸자를 주석 처리하면 코드가 잘 작동합니다 (물론 메모리 누수가있는 경우). (Visual Studio 2005)C++ (결국 벡터에 저장됩니다)에서 2D 동적 배열 삭제 문제

FrameData::FrameData(int width, int height) 
{ 
    width_ = width; 
    height_ = height; 

    linesize[0] = linesize[1] = linesize[2] = linesize[3] = 0; 

    // Initialise the 2d array 
    // Note: uint8_t is used by FFMPEG (typedef unsigned char uint8_t) 
    red = new uint8_t* [height]; 
    green = new uint8_t* [height]; 
    blue = new uint8_t* [height]; 

    for (int i=0; i < height; i++) 
    { 
     red[i] = new uint8_t [width]; 
     green[i] = new uint8_t [width]; 
     blue[i] = new uint8_t [width]; 
    }  
} 

FrameData::~FrameData() 
{ 

    // Delete each column 
    for (int i=0; i < height_; i++) 
    {   
     delete[] ((uint8_t*) red[i]); 
     delete[] ((uint8_t*)green[i]); 
     delete[] ((uint8_t*)blue[i]);  
    } 

    // Final cleanup 
    delete[] red; 
    red = NULL; 

    delete[] green; 
    green = NULL; 

    delete[] blue; 
    blue = NULL;  
} 

코드에 어떤 문제가 있는지 잘 모르겠습니다. 유일하게 다른 점은 충돌이 바로 문제의 원인이되어서는 안

FrameData myFrame; 
std::vector<FrameData> frames; 
...snipped... 
frames.push_back(myFrame); 

발생 어디 루프에서 이런 짓을, 다른 곳입니까? 올바른 것을 기억하면 push_back은 포인터 또는 참조를 저장하는 대신 사본을 만듭니다.

추신. 예, 벡터를 사용해야합니다. 그러나 나는 허용되지 않습니다.

추가 정보 :

연산자 = 및 복사 생성자가 정의되지 않았습니다. 나는 그것이 그 문제의 이유라고 생각한다.

+0

왜 소멸자에서 포인터를 형 변환하고 있습니까? – UncleZeiv

+1

빨강, 녹색 및 파랑은 어떻게 정의됩니까? – FireAphis

+1

복사 생성자 및 연산자 = FrameData에 대한 표시. –

답변

5

귀하의 문제는 다음과 같습니다.

FrameData myFrame; 
std::vector<FrameData> frames; 
...snipped... 
frames.push_back(myFrame); 

벡터는 당신이 밀어 요소의 사본을 만드는 당신은 당신의 복사 생성자 및/또는 클래스에 대한 operator= 무엇합니까? 아무 것도 정의하지 않은 경우 컴파일러에서 생성하는 기본 버전은 클래스 구성원의 복사본을 만듭니다. 이렇게하면 포인터 구성원 red, greenblue이 새 인스턴스에 복사됩니다. 그런 다음 복사 한 이전 인스턴스가 범위를 벗어나 포인터가 삭제되도록 파괴됩니다. 벡터에 복사 한 포인터는 포인터의 대상이 이와 같이 삭제되므로 유효하지 않은 포인터를 갖게됩니다.

원시 규칙이있는 경우 복사 생성자와이 상황을 올바르게 처리 할 을 만들고 포인터에 새로운 값이 지정되고 공유되지 않도록해야합니다. 인스턴스간에 소유권이 이전되었는지 여부

예를 들어, std::auto_ptr 클래스에는 원시 포인터가 있습니다. 복사 생성자의 의미는 포인터의 소유권을 대상으로 전송하는 것입니다.

클래스 에는 원시 포인터가 있습니다. 의미는 참조 카운팅을 통해 소유권을 공유하는 것입니다. 클래스에 대한 포인터를 포함하는 std::vectors을 처리하는 좋은 방법입니다. 공유 포인터가 소유권을 제어합니다.

또 다른 방법은 멤버 포인터 대신 벡터를 사용하는 것입니다. 멤버 포인터는 배열의 별칭 일 뿐이므로 벡터 대신 사용할 수 있습니다.

+0

+1 - 저는 같은 방식으로 대답 할 것입니다. 원래 포스터가 규칙 3을 따르지 않은 것처럼 보입니다. 복사 된 포인터를 삭제 한 다음 삭제합니다. –

+0

감사합니다. 복사 생성자를 추가하면 문제가 해결됩니다. 나는 이것이 나에게 좋은 교훈이라고 생각한다. – Extrakun

+0

복사 생성자를 만드는 경우 동일한 작업을 수행 할 연산자 =를 작성해야 할 수도 있습니다. –

0

copy_backup에 대한 올바른 내용이지만 FrameData에 적합한 복사 생성자 및 할당 연산자가 있습니까? 당신이 캐스트를 C 스타일을 사용 (또는 재 해석)해야하는 경우

C++에서
delete[] ((uint8_t*) red[i]); 

, 코드가 거의 확실히 잘못된 것입니다 : 여기에 캐스팅 이유를

또한

. 여기에 추측으로

1

FrameData 클래스에 대한 딥 복사 생성자와 할당 연산자가 없으면 컴파일러에서 push_back과 함께 사용할 복사 생성자를 생성한다는 것입니다. 자동으로 생성 된 생성자 및 대입 연산자는 멤버 별 복사를 수행하므로이 인스턴스에 얕은 복사본이 생성됩니다. 안타깝게도 소멸자는 사본에 대해 모르기 때문에 복사하는 동안 FrameData의 임시 복사본이 파괴되고 모든 데이터가 삭제됩니다.

나중에 프로세스에서 소멸자를 다시 호출하면 이중 자유가 생기고 다른 할당은 "사용 가능한"메모리의 일부를 사용했을 수 있습니다. 여기에서 힙 손상에 대한 좋은 이유 인 것처럼 보입니다.

이러한 문제를 찾는 가장 좋은 방법은 대개 ValGrind 또는 Purify와 같은 도구를 사용하여 문제를 찾아내는 것입니다.

1

이것은 단지 관찰 결과 에 대한 대답이 아닙니다. 다른 사람들이 지적했듯이 , 이것은 또한 당신의 충돌 문제를 해결합니다 :

당신의 프레임 데이터 과도한 복제를 방지하기 위해, 많은 수 있기 때문에

, 당신은

std::vector<FrameData *> frames; 

편집을 사용하는 것이 좋습니다 수 있습니다.