[완료][감사합니다^^]m_map를 쓰다가...

tkfkdgody의 이미지

안녕하세요..
m_map를 쓰면서 안풀리는 부분이 있어서 글을 씁니다.
자꾸 보다보니 자꾸 헤매기만 해서요..
코딩을 굉장히 못해서;;; 여기저기 찾아보면서 구현한것입니다.

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

if (it == m_map.end())
{
//기존 유저일 경우
Player* player;
player = m_map[account];
}

// 새로운 유저일 경우 player객체에 account 저장하여 map에 저장
Player* player = it->second;
player->m_account = account;
m_map[account] = player;

문제는 find 하여 새로운 유저에 대한 정보를 저장하는 위에 부분인데요...
처음부터 새로운 유저를 로그인 시키고 그 이후에도 다른 새로운 유저를 지속적으로 받는다고 가정하에 테스트 하면,

!!! 제일 처음 들어오는 유저는 원래 저장되어 있지 않은 유저임에도 '기존 유저일 경우' 루틴을 타버립니다.
그런데 이게 참 이상한게 첫번째 들어오는 유저만 그렇고요 그 이후에 새로 들어오는 유저는 정상적으로 '새로운 유저일 경우'루틴만
타거든요...;;;

왜 이러는지 자꾸 봐도 갈피를 잡지를 못하겠네요...
map을 포함한 코딩에 문제가 있는건 아닐까? 위에 루틴이 타기전 다른 부분에서 문제가 있는건지? 하는 여러 가지
경우의 수를 생각하고 따져봐야 하는데 더 혼란스럽네요..

미천한 저에게 미약하나마 조언 좀 부탁드리겠습니다..


klara의 이미지

기존 유저와 새로운 유저에 대한 정의와 m_map이 무엇인지가 적혀있지 않으므로 정확한 답변은 불가능하지만 상식적인 선에서 생각해보면 비교하는 조건이 잘못된 듯 하네요.

find에서 반환되는 반복자가 end()인 경우는 map안에 들어있지 않는 경우입니다.

tkfkdgody의 이미지

기존 유저는 맵과 객체 안에 저장된 유저를 말하고요
새로운 유저는 처음 로그인한 유저를 말합니다.

기존 유저가 없더라도 아무것도 저장되지 않은 맵안에
계속 새로운 유저가 접속한다고 하면 '새로운 유저'루틴으로 들어
가야 하는데 이게 안됩니다.
예를 들면)
1, 2, 3... 순서대로 처음 로그인한 유저라면
1, 2, 3모두 if문을 타지 않고 '새로운 유저'루틴으로 들어가야
하는데요, 유독 1번만 if문, 즉 '기존 유저'루틴도 타버리는 현상
이에요..

저도 비교가 이상한가 싶어서 '!=' 로도 해보고 밖으로 빼보고
별짓을 다해봤는데 아니더라고요.. ;;;

위에거 말고 한가지 더 추가적으로 질문 좀 드릴게요..
맵 안에 있는 키값을 전부 하나씩 읽을려면 어떤 방법을 써야 하나요?
키값에 대응되는 값만 추출되는건 아니지요??

늦은 밤 정말 답변 감사합니다~ 좋은 밤 되셨으면 좋겠네요;;
이미 그러실지도...^.^

klara의 이미지

앞에서도 말씀드렸지만 find가 end()를 반환하는건 키를 찾지 못했을 경우입니다.
1이 새로운 유저라면 m_map에 들어있지 않을 테고 당연히 find는 end()를 반환하며, if 문의 조건을 만족하므로 if문안으로 들어갑니다.
그리고 적혀있는 내용을 보면 m_map이 어떤 템플릿 인자로 선언되있는지 추측할수야 있지만, 이정도는 적어주셔야 답변하는 사람이 그 수고를 덜겠지요...
마지막으로 키값을 전부 읽을려면 반복자를 이용해서 begin()부터 end()까지 읽어가면 됩니다.

tkfkdgody의 이미지

선언 부분입니다..
std::map[char*, Player*] m_map;
(꺽쇠 안의 데이타가 안보이네요 그래서' [ ] '로 대체했습니다)
관련된 부분..입니다..
Player::Player()
{
m_account = NULL;
}

처음 생성하면서의 문제는 아닐까 하여 올려봅니다.

if (it != m_map.end())
{
//기존 유저일 경우
Player* player;
player = m_map[account];
}

맵에 관련된 부분은 이게 다네요...

답변 감사합니다..

klara의 이미지

좀더 소스코드가 무엇을 의도한것인지에 대해 자세히 적어주세요.

기존 유저인 경우에만 if 문을 적용시키고, 그 다음에 새로운 유저에 대한 부분을 기존유저와 새로운 유저 모두 적용되는건가요?
이부분에서 이미 '기존유저'를 '새로운유저'로서 다루고 있으니 프로그램 자체가 모순적입니다.

그리고 find에서 찾지 못한 경우는 it는 end()입니다.
그러므로 이 it로부터 first나 second를 참조하는 것은 예상치못한 결과를 초래합니다.

이부분은 쓸데없는 참견일지도 모를겠습니다만, account가 무엇인지 모르겠지만 키의 형으로 볼때 char*로 되어있는데, string을 쓰지 않고 메모리관리를 해줘야 하는 char*를 키값이나 Player의 멤버로 이용하는 이유가 무엇인가요?

마지막으로 저상태로라면 키로 이용되는건 account의 문자열이 아니라 포인터주소를 비교하는 셈이고, 특히 player->m_account = account; 이런 부분은 보통은 strcpy를 이용할 부분인데, 포인터를 키로 하고 포인터를 그대로 대입하는게 의도하신 바인가요...?

tkfkdgody의 이미지

유저가 로그인 할 시 '기존 유저'가 있을경우 그 유저의 객체만 얻어오고요, '새로운 유저'이면 객체 새로 생성하고
맵 안에 저장을 합니다. 모순적이라고 하신 말씀이 맞네요..;;
바뀐 구현은 아래와 같습니다.
std::map[char*, Player*]::iterator it = m_map.find(account);

if (it == m_map.end())
{
//기존 유저일 경우
Player* player;
player = m_map[account];
}
else << 모순된다고 하신 부분
{
// 새로운 유저일 경우 player객체에 account 저장하여 map에 저장

Player* player = new Player(); <<< 개선 부분
strcpy(player->m_account, account); <<< 개선 부분
m_map[account] = player;
}
이렇게 하라는 말씀이신가요..

char* -> string에 대한 건 잘 몰라서요.. 바꾸는건 좀 찾아봐야겟네요..

klara의 이미지

Quote:
char* -> string에 대한 건 잘 몰라서요
이 말씀은 여기서 char*는 문자열로서만 쓰고 있다고 생각해도 괜찮은 건가요..?
그렇다면 char*대신에 std::string을 이용하시기를 강력하게 추천합니다.
작성하신 거처럼 char*를 이용하면 댕글링 포인터로 인한 segmentation fault로 프로그램이 쉽게 죽을 듯합니다.
시간을 투자해서라도 std::string에 대해 알아보시고 이용하시는게 좋습니다. 오히려 char*보다 훨씬 쉽고 직관적이기 때문에 투자해야할 시간도 얼마 안될것입니다.
이후로 m_account나 account등은 char*대신에 std::string으로 생각하고 설명하겠습니다.

앞에도 두번 적었듯이 end()가 반환되면 map에 들어있지 않은 것입니다. 그러므로 if 문이 기존 유저를 위한 것이라면 ==이 아니라 !=로 비교해야합니다.

그리고 (이것도 적혀있지 않아서 추측해보자면) 결국엔 Player에 대한 포인터를 얻는게 목적인듯 한데, 이렇게 구현하면 결국 player가 지역변수이므로 가져오는건 불가능합니다.

Player *player = 0;
if (it == m_map.end()) { // 새로운 유저일 경우 player객체에 account 저장하여 map에 저장
	player = new Player();
	player->m_account = account;
	m_map[account] = player;
} else
	player = it->second;

제가 추측한 목적이 맞다면 이런식으로 구현하면 되겠지요.
tkfkdgody의 이미지

어디서 흐를 메모리 누수가 있을지 모르고 전에 답변해주신거 때문에 std::string로 바꿀려고 찾아보고 있습니다.

지속적인 답변 정말 감사합니다.. 하루 잘 마감하십시오~

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.