2009-10-15 4 views
0

지도 아래 '위젯'은 어떤 이유로 든 1 크기입니다. 그것이 끝나면 4가 있어야합니다.회원 추가시 C++지도 객체가 늘어나지 않음

출력 : 여기에

Widget: widget_ram_label:layout_bar:0 1 
Widget: widget_ram_active:layout_bar:0 1 
Widget: widget_ram_total:layout_bar:0 1 
Widget: widget_wlan0_label:layout_bar:0 1 

위젯입니다 :

std::map<const char *, Widget *> widgets; 

을 그리고 여기에 코드입니다 :

void Generic::BuildLayouts() { 
    for(std::map<const char*, std::vector<widget_template> >::iterator l = 
     widget_templates.begin(); l != widget_templates.end(); l++) { 
     std::vector<widget_template> layout = l->second; 
     for(unsigned int i = 0; i < layout.size(); i++) { 
      Json::Value *widget_v = CFG_Fetch_Raw(root, layout[i].key); 
      if(!widget_v) { 
       error("No widget named <%s>", layout[i].key); 
       continue; 
      } 
      Json::Value *type = CFG_Fetch_Raw(widget_v, "type"); 
      if(!type) { 
       error("Widget <%s> has no type!", layout[i].key); 
       delete widget_v; 
       continue; 
      } 

      Widget *widget; 

      char name[256]; 
      sprintf(name, "%s:%s", layout[i].key, l->first); 
      char tmp[256]; 
      int i = 0; 
      sprintf(tmp, "%s:%d", name, i); 

      while(widgets.find(tmp) != widgets.end()) { 
       i++; 
       sprintf(tmp, "%s:%d", name, i); 
      } 
      memcpy(name, tmp, 256); 

      if(strcmp(type->asCString(), "text") == 0) { 
       widget = (Widget *) new WidgetText(this, name, widget_v, 
        layout[i].row, layout[i].col); 
       std::cout << "Widget: " << name << " " << widgets.size() << std::endl; 
      } else { 
       error("Unknown widget type: %s", type->asCString()); 
      } 
      if(widget) { 
       widgets[name] = widget; 
      } 
      delete type; 

     } 
    } 
} 
+2

왜 C 문자열 조작으로 고문하고 있습니까? 그냥'std :: string'을 사용하십시오. – GManNickG

+0

변수로 루프 카운터'i'를 섀도 잉하고 있습니다. 문제의 원인은 아니지만 디버거 용이라 할지라도 독자에게는 혼란을 줄 수 있습니다. – Troubadour

답변

2

어쩌면 때문에 같은 버퍼에 모든 이름 포인터 poitns를? 왜냐하면 이름의 내용은 변하지 만지도의 이름에 대한 포인터의 값은 변하지 않기 때문입니다.

대신 std :: string을 사용해보십시오.

하면

#include <string > 
//... 
std::string name = "the name"; 

에 의해 버퍼 있으며, 여러분의 인생을 더 쉽고 안전하고 읽기 쉽게 만들 것이다

std::map< const std::string , Widget* > widgets; 

에 의해지도를 대체 이름을 바꿉니다.

서식을 지정하려면 std :: stringstream 또는 boost string algorithms을 사용하십시오.


예를의 시작이 코드 :

      char name[256]; 
      sprintf(name, "%s:%s", layout[i].key, l->first); 
      char tmp[256]; 
      int i = 0; 
      sprintf(tmp, "%s:%d", name, i); 

      while(widgets.find(tmp) != widgets.end()) { 
       i++; 
       sprintf(tmp, "%s:%d", name, i); 
      } 
      memcpy(name, tmp, 256); 

는 다음과 같이 기록 될 것입니다 : 아마 name의 주소를 해싱 것

Widget *widget = NULL; // always initialize your variables!!! 

std::stringstream name_stream; // this will let us format our string 
       name_stream << layout[i].key << ":" << l->first; 

std::string name = name_stream.str(); // now we got the string formated. 

std::stringstream tmp_stream; // same for tmp 
tmp_stream << name << ":" << i; // will automatically convert basic types, see the doc if you want specific formatting 

std::string tmp = tmp_stream.str(); // now we got the string formated. 

// the while loop have no sense : a map have only one value by key 
// if you want to have several values by key, use std::multi_map instead -- it don't work exactly the same though 
// for now i'll just assume you just need to find the value associated to the name: 


typedef std::map< const std::string, Widget* > WidgetMap; // for ease of writing, make a shortcut! ease your life! 
WidgetMap::iterator tmp_it = widgets.find(tmp); 

if(tmp_it != widgets.end()) 
{ 
// starting here I don't understand you code, so I'll let you find the rest :) 
} 
+0

그러면 출력의 각 줄마다 이름이 다른 이유는 무엇입니까? – Scott

+0

@Scott :'memcpy' 호출은 버퍼의 내용을 변경하기 때문에. 'name'의 값은 여전히 ​​주소입니다. – eduffy

+0

std :: string을 사용하여 형식 문자열을 어떻게 작성합니까? 나는 결코 그것을 이해할 수 없으므로, 나는 숯불 포인터를 붙였습니다. – Scott

0

. std:string을 사용하십시오.

1

std::string을 사용하는 대신 버퍼를 사용하기 전에 strdup 수 있습니다. std::map을 무료로 이용할 때 무료로 보내주십시오.

+0

열쇠가 이미 있고 삽입이 일어나지 않았다면 (사람이 힘들게 만듭니다) 열쇠를 치우십시오. – UncleBens

3
std::map<const char *, Widget *> widgets; 

이 작업을 수행하지 마십시오. char*을지도 키로 사용하지 마십시오. 지도는 해당 키에 대해 std::less이라는 표준 비교를 사용하며 포인터에 대한 주소를 비교합니다.

호감을 갖고 std::string을 사용하십시오. 일단 이것을 마스터하면 C 문자열을 다시 처리하려고 할 수 있습니다.

2

지도가 C 스타일 문자열을 올바르게 비교하는 방법을 알지 못합니다. C 스타일 문자열을지도의 키로 사용하려면 적절한 비교자를 제공해야합니다. 예를 들어, 다음과 같이 수행 할 수 있습니다.

inline bool str_less(const char *s1, const char *s2) { 
    return strcmp(s1, s2) < 0; 
} 

... 
std::map<const char *, Widget *, bool (*)(const char *, const char *)> widgets(str_less); 

원하는 경우 비교기를 클래스 기반 펑터로 구현할 수 있습니다.

하지만 그게 전부는 아닙니다. 지도에서 const char * 키의 메모리 관리 방법을 알지 못합니다.로컬 단기 버퍼에 대한 포인터를 키로 맵에 전달하고 있습니다. 이것은 전혀 쓸모가 없다. const char * 키의 경우 키 메모리를 직접 관리해야합니다. 예를 들어, 각 키를 동적으로 할당하고 동적으로 할당되고 올바르게 초기화 된 키 버퍼에 대한 포인터를 맵에 전달할 수 있습니다. 그리고 나중에지도가 망가질 때가되면이 모든 키 버퍼를 수동으로 할당 해제해야합니다.

이 모든 것이 목에 주요 고통입니다. 이런 이유로 C 스타일의 문자열이 아니라 'std :: string'을 키 유형으로 사용하는 것이 훨씬 낫습니다.

관련 문제