문제

그래서 작업이 끝나면 해제하고 싶은 콘텐츠가 포함된 2D 동적 배열이 있습니다.그러나 소멸자 이후에 계속 힙 손상이 발생합니다.소멸자를 주석 처리하면 코드가 제대로 작동합니다(물론 메모리 누수와 함께).(비주얼 스튜디오 2005)

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은 포인터나 참조를 저장하는 대신 복사본을 만듭니다.

추신.예, 벡터를 사용해야 합니다.하지만 나는 그렇게 할 수 없습니다.

추가 정보:

연산자= 및 복사 생성자가 정의되지 않았습니다.그게 문제의 원인인 것 같아요.

도움이 되었습니까?

해결책

문제는 여기서 짐작한 대로입니다.

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

벡터는 사용자가 삽입하는 요소의 복사본을 만듭니다.복사 생성자 및/또는 무엇을 가지고 있습니까? operator= 네 수업 때문에?아무것도 정의하지 않은 경우 컴파일러가 생성하는 기본 버전은 단순히 클래스 멤버의 복사본을 만듭니다.그러면 포인터 멤버가 복사됩니다. red, green 그리고 blue 새 인스턴스로.그런 다음 복사한 이전 인스턴스는 범위를 벗어나면 삭제되어 포인터가 삭제됩니다.그러면 포인터의 대상이 삭제되므로 벡터에 복사한 포인터는 유효하지 않은 포인터를 갖게 됩니다.

경험상 좋은 규칙은 원시 포인터 멤버가 있는 경우 복사 생성자를 만들고 operator= 포인터에 새로운 값이 부여되고 공유되지 않거나 소유권이 인스턴스 간에 전송되는지 확인하여 이 상황을 올바르게 처리합니다.

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

그만큼 boost::shared_ptr 클래스에는 원시 포인터가 있습니다. 의미는 참조 계산을 통해 소유권을 공유하는 것입니다.이것은 처리하는 좋은 방법입니다 std::vectors 클래스에 대한 포인터가 포함되어 있습니다. 공유 포인터가 소유권을 제어합니다.

또 다른 방법은 벡터를 사용하여 멤버 포인터를 대신하는 것입니다. 멤버 포인터는 어쨌든 단순히 배열의 별칭이므로 벡터는 좋은 대체물입니다.

다른 팁

FrameData 클래스에 대한 깊은 복사 생성자와 할당 연산자가 없으면 컴파일러가 push_back과 함께 사용할 복사 생성자를 생성한다는 직감이 듭니다.자동으로 생성된 복사 생성자와 할당 연산자는 멤버별 복사를 수행하므로 이 인스턴스에서는 얕은 복사본이 생성됩니다.불행하게도 소멸자는 복사본에 대해 알지 못하므로 복사하는 동안 FrameData의 임시 복사본이 파괴되어 모든 데이터를 가져갈 가능성이 높습니다.

프로세스 후반에 소멸자를 다시 호출하면 이중 해제가 발생하고 다른 할당에서 "사용 가능한" 메모리의 일부를 사용했을 수도 있습니다.여기에서 힙 손상이 발생하는 타당한 이유인 것 같습니다.

이와 같은 문제를 찾는 가장 좋은 방법은 일반적으로 ValGrind 또는 Purify와 같은 도구를 사용하여 문제를 정확히 찾아내는 것입니다.

이것은 귀하의 질문에 대한 답변이 아닙니다, 단지 관찰 일뿐입니다.

프레임 데이터가 클 수 있으므로 과도한 복사를 피하기 위해 다음을 사용하는 것이 더 나을 수도 있습니다.

std::vector<FrameData *> frames;

편집하다:다른 사람들이 지적했듯이 이것은 충돌 문제도 해결합니다.

push_back이 복사본을 만드는 것은 맞지만 FrameData에 적합한 복사 생성자와 할당 연산자가 있습니까?

또한 출연진이 여기에 있는 이유는 다음과 같습니다.

delete[] ((uint8_t*) red[i]);

C++에서 C 스타일(또는 재해석) 캐스트를 사용해야 한다면 코드가 거의 잘못된 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top