요즘은 ATL에서 CString을 지원하면서 std::string을 사용할 일이 줄어들긴 했지만, 여전히 유용한 클래스임에는 틀림없다.

가끔 MFC등 윈도용으로 개발된 클래스를 포팅해야 할 때 제일 문제가 되는 것 중에 하나가 CString이기도 한데 -_-
여튼. std::string에서 아쉬운 부분중에 하나인 ReplaceAll 함수를 간단히 구현해 보자.

   

#include <string>

 

typedef std::basic_string<TCHAR> _tstring;

 

_tstring replace_all( const _tstring& source, const _tstring& pattern, const _tstring& replace )

{

_tstring result = source;

_tstring::size_type pos = 0;

_tstring::size_type offset = 0;

_tstring::size_type pattern_len = pattern.size();

_tstring::size_type replace_len = replace.size();

 

while ( ( pos = result.find( pattern, offset ) ) != _tstring::npos )

{

result.replace( result.begin() + pos, result.begin() + pos + pattern_len, replace );

offset = pos + replace_len;

}

return result;

}

 

출처 : http://blog.daum.net/studiocoma/6800925

신고
블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

 map과 multimap은 '연관 컨테이너'입니다. 모든 연관 컨테이너(set, multiset, map, multimap)는 '노드 기반 컨테이너'입니다. 또 모든 연관 컨테이너는 균형 2진 트리로 구현됩니다. 균형 2진 트리는 보통 레드-블랙 트리를 사용합니다. map은 key와 value의 쌍으로 구성된 데이터 셋의 집합입니다. 여기서 key는 유니크합니다. multiset도 map과 같이 key와 value의 쌍으로 구성된 데이터 셋의 집합입니다. 단, multiset은 map과 달리 중복된 key가 존재할 수 있습니다.

 

map의 주요 개념을 그림으로 표현하면

map_개념.png 

set과 map은 데이터의 key가 유니크합니다.

 

multiset의 주요 개념을 그림으로 표현하면

multimap_개념.png 

multiset과 multimap은 같은 key값의 데이터를 컨테이너에 저장할 수 있습니다.

 

map, multimap의 주요 특징과 함수

 map도 set처럼 데이터를 추가하는 push_? 류의 함수를 가지고 있지 않습니다. 삽입(insert)한다는 의미에서 insert() 함수를 가지고 있습니다.

map의 특징은 key와 value의 쌍으로 데이터를 저장합니다. 그리고 key값을 이용하여 빠르게 value값을 찾을 수 있습니다. 연관 컨테이너에서 유일하게 [] 연산자 중복을 제공합니다.

 

기본적인 map 예제

#include <iostream>
#include <map>
using namespace std;
void main( )
{
    map<int , int > m;

    m[5] = 100;
    m[3] = 50;
    m[7] = 80;
    m[2] = 100;
    m[4] = 100;

    cout << m[5] << endl;
    cout << m[3] << endl;
    cout << m[7] << endl;
    cout << m[2] << endl;
    cout << m[4] << endl;
}
  1. 100
    50
    80
    100
    100

map은 key와 value의 쌍으로 구성된 데이터들의 집합입니다. []연산자의 인덱스는 key이며 인덱스가 가리키는 메모리 값이 value입니다.

주의할 점은 m[5] = 100 연산에서 5라는 key가 없으면 노드 '추가'가되며 5라는 key가 있으면 '갱신'이 됩니다. 아래에서 공부합니다.

그림으로 설명하면..

map_간단_코드.png

map의 트리 그림입니다.

map_데이터_추가.png 

map의 key값 5로 value를 접근하는 그림입니다.

map_데이터_접근.png 

 

 map은 key와 value의 쌍을 pair 객체로 저장합니다. STL의 쌍을 이루는 모든 요소는 pair 객체를 사용합니다.

위 예제는 insert()함수를 사용하여 아래 예제로 바꿀 수 있습니다.

#include <iostream>
#include <map>
using namespace std;
void main( )
{
    map<int , int > m;

    m.insert( pair<int,int>( 5, 100) );
    m.insert( pair<int,int>( 3, 50) );
    m.insert( pair<int,int>( 7, 80) );
    m.insert( pair<int,int>( 2, 100) );
    pair<int,int> pr( 4, 100);
    m.insert( pr );

    cout << m[5] << endl;
    cout << m[3] << endl;
    cout << m[7] << endl;
    cout << m[2] << endl;
    cout << m[4] << endl;
}

  1. 100
    50
    80
    100
    100

 map은 key, value를 pair 객체로 각각 first와 second에 저장합니다.

그림으로 표현하면

map_pair_객체.png 

 

 

반복자를 사용한 모든 key, value 출력 예제

#include <iostream>
#include <map>
using namespace std;

void main( )
{
    map<int , int > m;

    m[5] = 100;
    m[3] = 50;
    m[7] = 80;
    m[2] = 100;
    m[4] = 100;

    map<int, int>::iterator iter;
    for( iter = m.begin(); iter != m.end() ; iter++)
        cout << "m["<<(*iter).first <<"]: " << (*iter).second << endl;

    cout << "==============" << endl;
    for( iter = m.begin(); iter != m.end() ; iter++)
        cout << "m["<<iter->first <<"]: " << iter->second << endl;
}
  1. m[2]: 100
    m[3]: 50
    m[4]: 100
    m[5]: 100
    m[7]: 80
    ==============
    m[2]: 100
    m[3]: 50
    m[4]: 100
    m[5]: 100
    m[7]: 80

 map도 양방향 반복자를 제공합니다.

그림으로 간단하게..

 map_반복자.png

 

 

연관 컨테이너는 모두 동일한 함수군을 가지며 동작 방식도 같습니다.

map의 검색 함수들입니다.

#include <iostream>
#include <map>
using namespace std;

void main( )
{
    map<int , int > m;

    m[5] = 100;
    m[3] = 50;
    m[7] = 80;
    m[2] = 100;
    m[4] = 100;

    map<int, int >::iterator iter;

    iter = m.find( 5 );
    if( iter == m.end() )
        cout << "없음!" << endl;
    else
        cout << "m["<<iter->first <<"]: " << iter->second << endl;

    iter = m.lower_bound( 5 );
    if( iter == m.end() )
        cout << "없음!" << endl;
    else
        cout << "m["<<iter->first <<"]: " << iter->second << endl;

    iter = m.upper_bound( 5 );
    if( iter == m.end() )
        cout << "없음!" << endl;
    else
        cout << "m["<<iter->first <<"]: " << iter->second << endl;

    pair< map<int, int>::iterator, map<int, int>::iterator> iter_pair;
    iter_pair = m.equal_range(5);

    if( (iter_pair.first) == m.end() && (iter_pair.second == m.end()) )
        cout << "없음!" << endl;
    else
    {
        cout << "m["<< iter_pair.first->first <<"]: " << iter_pair.first->second <<" ~ ";
        cout << "m["<< iter_pair.second->first <<"]: " << iter_pair.second->second <<endl;
    }
}
  1. m[5]: 100
    m[5]: 100
    m[7]: 80
    m[5]: 100 ~ m[7]: 80

 동작은 set에서 설명했으므로 패스~!

그림으로 설명하면...

map_검색_함수.png 

 

 

 

마지막으로 multimap 예제입니다.

map과 다른 점은 [] 연산자가 없으며 key 값이 중복될 수 있습니다.

#include <iostream>
#include <map>
using namespace std;

void main( )
{
    multimap<int , int > m;

    m.insert( pair<int,int>( 5, 100) );
    m.insert( pair<int,int>( 3, 50) );
    m.insert( pair<int,int>( 7, 80) );
    m.insert( pair<int,int>( 2, 100) );
    m.insert( pair<int,int>( 4, 100) );
    m.insert( pair<int,int>( 7, 200) );
    m.insert( pair<int,int>( 7, 300) );

    pair<multimap<int,int>::iterator, multimap<int, int>::iterator > iter_pair;
    iter_pair = m.equal_range( 7 );
    multimap<int,int>::iterator iter;
    for( iter = iter_pair.first ; iter != iter_pair.second ; iter++)
        cout << "m["<< iter->first <<"]: " << iter->second <<' ';
    cout << endl;

}
  1. m[7]: 80 m[7]: 200 m[7]: 300

 설명은 multiset과 같습니다.

아래는 위 예제의 그림입니다.

multimap_equal_range(1).png  

 

 

 

여기까지 STL의 컨테이너를 마무리합니다.

C++ 표준에 추가된 해쉬 컨테이너는 다음에 공부합니다. 

출처 : http://coolprogramming.springnote.com/pages/4826369

 

최근엔 hesh_map 등이 더 인기가 있는거 같은..

쓰기에는 map 과 같은 인터페이스에 using namespase std 가 아닌 stdext 를 쓴다

자세한 레퍼렌스는 http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(HASH_MAP);k(DevLang-%22C%2B%2B%22);k(TargetOS-WINDOWS)&rd=true 를 참고하자

신고
블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소


실전 STL 플밍.. 소스 참고..
신고
블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

블로그 > 박후의 블로그
원본 http://blog.naver.com/parkhooman/90006821404

데브피아의  윤용한 / yonghany 님의 STL 강좌를 퍼 담았습니다.

님두 어떤 원서를 기초로 해서 쓰신건데 STL 기초에 도움이 많이 될것 같네요.


신고
블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

Tag 강좌

//////////////// 파일의 모든 내용 읽고 출력 //////////////// p161
//cout를 위해, ifstream을 위해, vector를 위해, string을 위해, for_each를 위해 각각 해더 추가

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>

//for_each에서 string출력에 사용할 단항 함수 정의
void print_str(const std::string &str)
{
 std::cout << str << std::endl;
}

...

using namespace std;

ifstream file("test.txt");
if(!file)
{
 cerr << "Can't open file " << enld;
 exit(0);
}

// file로부터 문자열을 읽으면서 vector에 저장
vector<string> strlist;
string temp;
while(file >> temp)
{
 strlist.pushback(temp);
}
file.close();

// vector에 담긴 모든 string을 출력
for_each(strlist.begin(), strlist.end(), print_str);


//////////////// 파일 복사 //////////////// p140
#include <iostream>
#include <fstream>
#include <string>

int main(int argc, char *argv[])
{
 using namespace std;

 if(argc != 3) return 1;

 string file1(argv[1]), file2(argv[2]);
 ifstream in(file1.c_str(), ios_base::binary); // 복사할 파일 바이너리로 읽고
 ofstream out(file2.c_str(), iso_base::binary); // 복사본 파일 바이너리로 쓸준비

 out << in.rdbuf();  // 여기서 복사 진행

 return 0;
}

//////////////// 조건이 맞으면 출력 //////////////// p141
#include <iostream>
#include <fstream>
#include <string>

template<typename t>
void if_cond_is_true_write_rst(
 std::string filename,
 std::streampos cond_pos, t cond,
 std::streampos target_pos, t rst)
{
 using namespace std;
 
 // 읽기 쓰기 가능하게 파일을 연다
 fstream file(filename.c_str(), ios_base::in | ios_base::out);

 // 지정된 위치로 cond_pos 이동
 file.seekg(cond_pos);

 t real;
 file.read(&real, sizeof real);

 if(real == cond)
 {
  file.seekg(target_pos);
  file.write(&rst, sizeof rst);
 }
}
... 중략 (main 함수 등)
if_cond_is_true_rst("cond.txt", 10, 'J', 0, '-');

//////////////// 파일 크기 출력 //////////////// p144
#include <iostream>
#include <fstream>
#include <iterator>
#include <limits>

...
using namespace std;
string filename;
...

// 파일을 열고 맨 끝으로 옮긴다. (ate는 파일을 열자마다 EOF로 가게 한다)
ifstream in1(filename.c_str(), ios_base::ate);
streampos end = in1.tellg();  // EOF인 현재 위치를 받아온다
cout << "Size : " << end << endl; // 출력
in1.close();

ifstream in2(filename.c_str(), ios_base::binary);
// 파일 크기 계산
streamsize size = distance(istreambuf_iterator<char>(in2),
 istreambuf_iterator<char>());
cout << "Size : " << size << endl;
in2.close();

//////////////// 정렬 문제 //////////////// p149
//영수증 출력 문제

#include <iostream>
#include <iomainp>
#include <string>

using namespace std;

struct item{ char name[32]; int price; int num;};

void print_title(
 const string &kind, const string &price, const string &number)
{
 cout << setw(15) << kind << setw(10) << price <<setw(10) << number << endl;
}

void print_item(const item & item)
{
 cout << setw(15) << item.name << setw(8) << item.price << "원"
  << setw(8) << item.num << "개" << endl;
}

void print_total(int price)
{
 cout << setw(33) << price << "원" << endl;
}

...
item itmes[3] = {
 {"가나초콜릿", 900, 1}, { "파워에이드", 900, 1}, {"감자깡",450,2}
};

print_title("종류", "가격", "수량");
int price(0);
for(size_t i(0); i < sizeof items / sizeof (item); i++)
{
 print_item(items[i]);
 price += items[i].num * items[i].price;
}
print_total(price);


신고
블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소