소멸자 호출에 관련된 문제입니다...

tkfkdgody의 이미지

안녕하세요
유저 로그인 처리 후 유저의 자료를 저장합니다. 유저가 계속 활동시 저장된 유저의 정보를 가지고
유저에 관련된 부분들의 자료를 갱신하는 부분을 구현중에 있는데요..
같은 유저의 정보를 받아서 처리를 할려고 하는데 처음에만 m_map에서 find하고 소멸자가 호출되면서
저장된 유저의 정보가 없어져버리네요.
소스를 보고 설명을 드리자면,

처음 들어온 유저가 있으면 아래 Login함수와 같이 유저 정보를 m_map 에 저장합니다.
void PlayerCtrl::Login(unsigned int forMap, const char* account)
{
isOnline = true;

std::map::iterator it = m_map.find(account);

Player* player = 0;
if (it != m_map.end())
{
//기존 유저일 경우
player = it->second;
}
else
{
// 새로운 유저일 경우
player = new Player();
player->m_account = account;
m_map[forMap] = player;
}

유저의 패킷은 유저 활동시간에 계속 오게 되는데 그 정보들을 갱신하기 위해 먼저 같은 유저의 객체를 뽑습니다.
Player* PlayerCtrl::findUser(unsigned int forMap)
{
std::map::iterator that = m_map.find(forMap);
if (that == m_map.end())
{
return &anon;
}
return that->second;
}
로그인 함수의 경우는 처음 유저가 로그인 할때 한번만 호출이 되고요, findUser함수의 경우는 지속적으로 호출되는데요

처음에 실행을 하면 로그인 함수를 실행하고 나서 findUser함수를 탑니다.. 처음엔 findUser함수에서 유저정보 객체를 잘 찾습니다.
그런데 두번째 findUser함수부터는 m_map에 저장되 있던 정보들이 없어져버렸습니다..
한참을 헤매다 소멸자 호출시 프린트를 찍어봤는데 2번째 findUser함수를 탈때 ~Player()소멸자가 그 이후로 계속 호출이 되더라고요.

이걸 어찌해야 할지 난감하네요.;;
선언 부분은 이렇습니다..

class Player
{
public:
Player();
~Player();
};

class PlayerCtrl : public BaseThread
{
private:
std::map m_map;
public:
void Login(unsigned int forMap, const char* account);
Player* findUser(unsigned int forMap);
};

자세하게 쓴다고 썼는데 설명에 부족하지는 않을런지..
흠.. 답글 부탁드리겠습니다..

ikpil의 이미지

Login 함수에서 플레이어를 담으시는것으로 보입니다.
그런데 플레이어 객체에 대한 포인터를 담는것이기 때문에, 주위를 해야 합니다.

new를 통해서 객체를 생성하면 자동으로 생성자는 호출은 되지만,
map안의 데이터를 삭제 할때, delete를 시켜주지 않으면, 소멸자는 영영 호출되지 않는 특징이 있습니다.

현재 소스코드에서는 소멸자를 호출하는 곳이 안보이기 때문에,
어딘가에서 delete를 시켜주기때문에, map안의 데이터중 second인 포인터의 대상이 없어지는것으로 보여집니다.

명시적으로 delete 하기 전까지 데이터가 남아 있는것을 확인하실수 있으실겁니다(아래)

간단한 예제

#include <iostream>
#include <map>
 
using namespace std;
 
class CPlayer
{
public:
	CPlayer(int _a = 0) : a(_a) {};
	~CPlayer()
	{			
		cout << "소멸자 호출" << endl;
	}
private:
	int a;
};
 
void PushTest(int _i, map&lt;int, CPlayer*> &_TestMap)
{
	CPlayer * pPlayer = new CPlayer;
 
	_TestMap[_i] = pPlayer;
}
 
void PopTest(int _i, map&lt;int, CPlayer*> &_TestMap)
{
	delete _TestMap[_i];
        // 여기서 Map의 원소도 같이 날려줘야 합니당.
 
}
 
int main(void)
{					  
	map&lt;int, CPlayer*> TestMap;
 
	PushTest(1,TestMap);
 
	cout << "소멸자 호출 체크 부분" << endl;
 
	PushTest(2, TestMap);
 
	cout << "소멸자 호출 체크 부분" << endl;
 
	PopTest(1, TestMap);
 
 
 
}

klara의 이미지

Quote:
map안의 데이터를 삭제 할때, delete를 시켜주지 않으면, 소멸자는 영영 호출되지 않는 특징이 있습니다.

다소 오해의 소지가 있어 적습니다. 의도하신건 그게 아닐지도 모르겠는데, 얼핏보면 동적할당된 객체의 소멸자가 호출되지 않는 것이 map의 특징인듯하게 읽힙니다.
동적할당 객체의 소멸자 호출여부와 map은 전혀 관계없습니다.
map에 담겨있든 안담겨있든, delete로 해제하지 않으면 객체가 소멸되지 않았으니까 소멸자가 안불리는 것 뿐입니다.
ikpil의 이미지

정확 하십니다!

tkfkdgody의 이미지

답글 달아주셔서 감사합니다..

[인용]----------------------------------------------------------------------------------------
new를 통해서 객체를 생성하면 자동으로 생성자는 호출은 되지만,
map안의 데이터를 삭제 할때, delete를 시켜주지 않으면, 소멸자는 영영 호출되지 않는 특징이 있습니다.
현재 소스코드에서는 소멸자를 호출하는 곳이 안보이기 때문에,
어딘가에서 delete를 시켜주기때문에, map안의 데이터중 second인 포인터의 대상이 없어지는것으로 보여집니다.
----------------------------------------------------------------------------------------------
---> delete 부분을 아예 주석처리하고 하는데도 소멸자가 계속 호출이 됩니다.;;; 계속 소멸자가 호출이 되서
아예 확인에 필요한 루틴은 주석처리해버리고 해봤습니다..;
한번 findUser함수를 탈때마다 소멸자가 호출이 되네요..

정성스럽게 답글 달아주셔서 정말 감사합니다. 예제까지 해서 올려주시고 감격했습니다.. 꾸벅

ikpil의 이미지

new로 만든 객체의 소멸 시점
1. 윈도우 창(프로그램)이 종료될 때
2. 명시적으로 delete 시켜 주었을 때

이 두 가지 경우 밖에 없는것으로 알고 있습니다.

cynicjj의 이미지

return &anon;

이 부분에서 anon 은 뭔가요?

tkfkdgody의 이미지

anon은

Player anon;

입니다..

흠.. delete도 호출하지 않고 프로그램도 종료되지 않는데 소멸자가 호출이 되다니;;

답변 감사합니다..

kslee80의 이미지

Player anon; 이 findUser() 안에 로컬 변수로서 선언되어 있다면,
findUser() 함수 종료시에 anon 의 소멸자가 호출되게 됩니다.

cynicjj의 이미지

anon 이 로컬 변수라면 findUser() 함수가 끝날때
소멸자가 호출됩니다.

임시로 anon 을 삭제하시고 테스트 해보세요.

그런데, 그렇다고 해도 소멸자 호출은 설명이 되는데
맵의 내용이 날라가는 이유는 설명이 안 되는것 같네요.

klara의 이미지

질문하시기 전에 지금 적어주신 소스들을 한번 되살펴보시기바랍니다.
소스 전체를 올리기 힘들어서 부분부분 꺼내신듯 한데, 너무 뒤죽박죽입니다.
예를 들면, player->m_account 와 같이 Player 클래스에는 m_account라는 멤버가 있는 거처럼 쓰고 있는데, Player 클래스의 정의에는 멤버변수가 전혀 들어있지 않네요.
게다가 map에서 find함수는 키값으로 찾는 것인데, 똑같은 m_map이란 변수에서, find 할때는 m_map.find(account);와 같이 const char*인 변수로 찾고, 추가할때는 m_map[forMap] = player;와 같이 unsigned int로 추가하고 있으니 뭐가 키인지 알수가 없네요.
윗분들이 적으신 anon이라는 변수도 그 유래를 찾을수 없구요.
물론 소스 전체를 올려버리는 것도 좋진 않지만, 골라 올리실땐 이걸 다른 사람이 보고 뭐하는 소스인지 알수 있을지 생각해보시고 정리해서 올려주시면 더 답변닫기 좋을 듯합니다.

everydayrebooting의 이미지

소스에 특별한 문제점은 보이지 않는 것 같은데요..

m_map에서 정보가 사라진다 함은, player가 delete 된다는 의미인가요?

player anon 문제가 아니라면, player 파괴자에 break point 걸고,

call stack을 확인해서 어디서 delete 했는지 확인해 보면 나오지 않을까요?

tkfkdgody의 이미지

[인용] by everydayrebooting
m_map에서 정보가 사라진다 함은, player가 delete 된다는 의미인가요?
player anon 문제가 아니라면, player 파괴자에 break point 걸고,
call stack을 확인해서 어디서 delete 했는지 확인해 보면 나오지 않을까요?

[답변]
우선 delete 하는 부분은 전부 주석 걸어버려서 제가 직접 delete하는 부분은 없습니다.
처음에는 m_map과 player 객체의 정보들이 잘 출력이 되는데요, 출력되고 한번 루틴이 끝나면
그 이후에 소멸자가 호출되서 player를 delete하는거 같습니다. player anon은 지역변수라서
by cynicjj 이 분이 하라는 데로 주석처리하고 해봤는데 똑같이 소멸자가 계속 호출되네요
리눅스 이클립스에서 코딩하는데 스레드 돌리면서 디버깅을 못 하고 있습니다.;; 찾아봐서 한다는게
여태 못 찾아봤네요 ;;

[인용] by xylosper
질문하시기 전에 지금 적어주신 소스들을 한번 되살펴보시기바랍니다.
소스 전체를 올리기 힘들어서 부분부분 꺼내신듯 한데, 너무 뒤죽박죽입니다.
[답변]
네..;; 자세히 적는다는게 맨날 요모냥으로 올려놓네요.. 다음부터는 좀 더 살펴서 올릴게요..;

흠 갑갑하군요..;; 많은 분들이 답글을 주셨네요 감사합니다..

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.