stl에서 new, delete 문제
class Frame
{
public:
Frame(void);
Frame(int frameNo) {score = new int[2]}; //다른 기능 생략...
~Frame(void);
int *score;
};
class Game
{
public:
Game(void) {currentFrame = newFrame()}
~Game(void){
for(list::iterator it = frames.begin(); it != frames.end();)
{
frames.erase(it++);;
}
}
Frame *currentFrame;
list frames;
Frame* newFrame(void);
bool throwDown(int pinCount);
};
Frame* Game::newFrame(void)
{
Frame *f = new Frame(currentFrameNo);
return f;
}
bool Game::throwDown(int pinCount)
{
if(pinCount < 0 || pinCount > 10)
{
return false;
}
if(!currentFrame->AddScore(pinCount))
{
return false;
}
checkFrameBonus(pinCount);
if(isNextFrame(pinCount))
{
currentFrameNo++;
[b]frames.push_back((Frame&)*currentFrame);
currentFrame = newFrame();
}
return true;
}
볼링 게임을 만드는 중인데 Game클래스의 멤버로 list을 가지고 Frame 객체를 throwDown함수에서 push_back했습니다.
new를 이용해서 Frame 객체를 할당한 이유는 local 변수로 할당해서 list에 추가하는 경우 그 함수가 끝나면 stack에서
사라지기 때문입니다.(제가 잘못 생각하는 경우일 수도 있는데 혹시 stl에 특정 함수내에서 지역변수로 할당한 객체를 삽입할 경우
다른 함수에서 사용이 가능한가요? 저는 stack이 사라지기 때문에 안될 것이라고 생각해서 위와 같이 했습니다.)
근데 정작 문제는 destructor에서 발생하네요. 위와 같이 파괴자를 작성하니 memory leak이 발생하는 것 같아서
Frame* fr = (Frame*)⁢
frames.erase(it++);
delete fr;
로 파괴자의 루프안을 수정하면 이중 해제로 에러가 발생합니다.
문제를 어떻게 해결해야 할까요?
ps 끝까지 읽어주셔서 감사합니다.
delete fr 부분에서
delete fr 부분에서 로컬변수인 it가 지워지게되는 것 아닌가요..?
함수 끝나면서 자동으로 파기될 때 에러가 뜨는게 아닌가 싶습니다.
Frame* fr =
Frame* fr = (Frame*)⁢
frames.erase(it++);
delete fr;
이건 잘못된 변환입니다. it는 어디까지나 반복자이지 컨테이너 내용물 그자체가 아닙니다. &it는 반복자의 주소이지, 그 내용물이 아닙니다. C형식의 캐스팅이 얼마나 위험한지를 알수 있지요.
지금 지우고있는 것은 반복자 그자체일 뿐만 아니라, 잘못된 형변환으로 인해 소멸자조차 제대로 호출될수 없는 상태입니다.
frames.push_back((Frame&)*currentFrame);
계속 찾아보고 있는데 문제는 frames.push_back((Frame&)*currentFrame); 이 부분에서도 문제가 발생하여
제대로 list에 삽입되지 못하고 있습니다.
어떤 식으로 해결해야 할가요?
복사 생성자 및
복사 생성자 및 대입연산자를 적절하게 구현해보세요.
STL은 모든 객체를 복사해서 집어넣습니다. 동적할당한 녀석을 집어 넣는다고 그녀석이 들어가는게 아니라 = 로 그녀석을 복사해서 집어넣게 됩니다.(복사생성자를 쓰는지 대입연산자를 쓰는지 기억이안나네요).
지금 Frame의 멤버가 포인터이기때문에 복사생성자나 대입연산자없이 복사를 하면 얕은 복사만 이루어지게됩니다.
소스가 읽기 힘들어서 안봤습니다만, 이런 문제라면 Frame의 동적할당은 필요가 없네요.
복사생성자, 연산자 오버로딩
Frame::Frame(const Frame& frame)
{
frameNo = frame.frameNo;
throwCount = frame.throwCount;
bonusCount = frame.bonusCount;
frameScore = frame.frameScore;
if(frameNo != 10)
{
score = new int[OTHER_FRAME];
}
else
{
score = new int[TEN_FRAME];
}
*score = *(frame.score);
}
Frame operator =(const Frame& frame)
{
frameNo = frame.frameNo;
throwCount = frame.throwCount;
bonusCount = frame.bonusCount;
frameScore = frame.frameScore;
if(score == NULL)
{
if(frameNo != 10)
{
score = new int[OTHER_FRAME];
}
else
{
score = new int[TEN_FRAME];
}
}
*score = *(frame.score);
}
다음과 같이 복사 생성자와 = operator 오버로딩 했습니다. 위 소스에 문제가 있는건가요?
구현그자체는
구현그자체는 문제없어보이네요.
*score = *(frame.score);
이게 의도한 바인지는 모르겠습니다만, 이걸로 런타임이나 컴파일시에 에러가 나진 않을테구요..
그리고 긴 코드를 올리실때는 code로 감싸서 적절하게 들여쓰기를 해주세요.
마지막으로 '문제가 된다'고 하셨는데 무슨 문제인가요?
*score = *(frame.score);
말씀하신 부분은 제가 실수한 부분이라 다음과 같이 수정하였습니다.
for(int i=0; i {
score[i] = frame.score[i];
}
그런대도 해결되지 않네요
코드는 코드블럭
코드는 코드블럭 안에 넣어주세요..
코드가 깨져서 frame의 타입을 어떻게 하셨는지 모르겠지만,
아마도
으로 했다면 별도의 대입 및 복사 연산자가 필요없습니다. 대신 메모리 관리는 직접 해야지요.
넣을때 포인터를 넣고..
지울때
로 해야겠죠.
물론
로해서 개체 자체를 넣을수도 있습니다. 이경우 넣는 순간 복사가 되어
리스트에 들어가므로 local변수가 지워질 문제는 없습니다.
대신 복사가 되는거니, 복사 연산자가 있어야겠지요.
이경우 frame이 없어질때
각각의 개체들도 없어집니다. 물론 따로따로 소멸자를 호출하면서요.
인용:볼링 게임을
위에도 적었지만, list에 추가될떄는 무조건 복사되어서 추가됩니다.
그렇기 때문에, 원래 객체가 스택에 있던 힙에 있던 상관없고, list내의 객체가 사라지는 것은 해당 list가 사라질때입니다.
댓글 달기