기본 콘텐츠로 건너뛰기

라벨이 cplusplus인 게시물 표시

unsigned type & loop

C/C++에는 여러가지 숫자변수형태가 있고, 이는 부호가 있는 것(signed)과 없는 것(unsigned)으로 나눌 수 있다. 오늘 할 이야기는 그 중에 하나 키가 크고요~...가 아니라 부호가 없는 것에 대한 저주스런 이야기이다. size_t i(delta); while ( i >= 0 ) { // blar blar... --i; } 이 소스는 CPU 100%를 쳐먹으면서 기계를 혹사시킬 것이다. 컴파일러나 라이브러리에 따라 그 구현이 다르겠지만, 보통 size_t는 unsigned long형이다. 십장생. i가 0이어도 루프는 한 번 더 돈다. 마지막에 i가 0이지만 감소연산을 때리면, i는 그것이 가질 수 있는 최대값으로 변모한다. 당연하지... unsigned니까. 결국 저 악마 같은 코드는 무한루프를 도는 것이다. 몇 년을 C/C++로 밥 벌어먹고 살아도 실수는 계속하기 마련인가?! 원본 위치: http://purewell.egloos.com/3417102

느린 GNU std::string

신이 내린 축복이라 생각했던 std::string. 삭막하던 C/C++에 string이란 타입을 선사해주신 SGI에게 감사하고 있었다. 가변길이 string. 생각만 해도 아힝~*이 절로 나온다. 그러나... 씨밤. 상당히 평범한 상황에서 그냥 char[]을 쓰는 것보다 느리다. 그도 그럴 것이, assign에서 Allocator를 돌리기 때문이다. 예를 보자. void testChar(const char* data) { char field[10][1024+1]; // data를 ' '로 파싱해서 field에 strncpy함. (귀찮아서 패스) } void testString(const char* data) { string field[10]; // data를 ' '로 파싱해서 field에 assign(ptr+pos, length)함. (귀찮아서 패스) } 뭐, 대충 이런 코드가 있다고 치자. 위 함수들을 상당히 큰 수만큼 돌렸다고 치자. 퍼포먼스는 얼마 정도 될까? 자료를 전부 공개할 수 없다는 점은 대충 이해하시라. (아니면 만들어서 돌려보시던가) 약 3.5배 정도 string이 느리다. 그도 그럴 것이 char는 (1024+1)*10을 미리 stack에 잡아놓고 call을 호출한다. 그러나 string은 string이라는 instance만 stack에 쌓여 있고, 실제 메모리는 data를 파싱하여 assign하는 동안 내부적으로 new(malloc)을 호출하여 heap에 메모리 덩어리를 할당받는다. 이게 위에서 stack 지랄하는 것보다 훨씬 느리다. testString에서 for문을 하나 더 넣어서 파싱하기 전에 field에 reserve(1024+1)을 하면 빨라질까? 아쉽게도 더 느려진다. 실험에서는 거의 2배가 넘게 느려졌다. 안습인데?! -_- 더욱 날 경악케 하는 것은 string[] 대신에 vector<string>에 push_back을 했을 경우는 st...

GNU의 std::string은 같은 문자열을 공유한다.

보통 std::map에서 key로 std::string을 많이 쓰는데, 쓸 때마다 부담스러웠다. 이유는 key는 std::map에서 node를 만들 때 instance를 새로 만들고 복제하기 때문이다. 그러나 GNU의 std::string은 동일한 문자열은 같은 메모리영역을 공유하도록 만들었다. 따라서 복제가 이뤄져도 실제로 데이터를 복제하는 것이 아니라 내부 레퍼런스 카운터만 올라간다. /usr/include/c++/x.x.x/bits/basic_string.[h|tcc] 파일을 까보면 _M_is_shared()라는 private method가 assign을 비롯하여 여기저기 쓰여 있는 걸로 보아 확실하다. 이를 나름 증명해보자면, 아래 소스를 컴파일해서 돌려보자. #include <iostream> #include <string> #include <map> using namespace std; map<string,void*> gMap; int main(int, char**) { string str1("Hello, world!"); string str2(str1); string str3; str3 = str1; string str4; str4.assign(str1); gMap.insert(map<string,void*>::value_type(str1, NULL)); cout << "str1: " << (void*)str1.c_str() << endl; cout << "str2: " << (void*)str2.c_str() << endl; cout << "str3: " << (void*)str3.c_str() << endl; cout << "str4:...