GSI

vector를 사용해서 객체를 저장할때 포인터 형으로 하게 되면
메모리 누수를 막기 위해서 객체를 항상 Delete 해줘야 한다.
솔직히 매번 Add, Delete, DeleteAll 등을 해줘야 하는 불편함이 전(??) 있었다. ^^
그래서 템플릿으로 하나 만들었다.
for-each 이건.. 왜 안되는지 ^^.. 암튼.. 현재걸로 조금 우선 사용해보자.

// 사용법 //
CGsiV<CTest> VectorArray;
VectorArray.Add(new CTest());
int size = VectorArray.GetVector()->size();

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// CGsiV
template <class T>
class CGsiV
{
public:
 CGsiV() {
  m_v.clear();
 }

 virtual ~CGsiV() {
  DeleteAll();
 }

 // Add
 void Add(T* t) {
  m_v.push_back(t);
 }

 // Delete
 bool Delete(T* t) {
  T* p;
  vector<T*>::iterator iter;
  for(iter = m_v.begin(); iter != m_v.end(); ++iter) {
   p = (*iter);
   if(p != NULL && p == t) {
    delete p;
    p = NULL;
    m_v.erase(iter);
    return true;
   }
  }
  return false;
 }

 // DeleteAll
 void DeleteAll() {
  T* p;
  vector<T*>::iterator iter;
  for(iter = m_v.begin(); iter != m_v.end(); iter++) {
   p = (*iter);
   if(p != NULL) {
    delete p;
    p = NULL;
   }
  }
  m_v.clear();
 }

 //GetVector
 vector<T*>* GetVector() { return &m_v; }

protected:
 vector<T*> m_v;
};

Posted by gsi
:

함수가 많을 경우 함수 포인터를 사용해서 배열로 사용하는 방법이 편할때가 있다.

그래서 STL의 vector을 사용해서 함수 포인터 정보를 배열로 저장하고
해당 함수들을 콜해서 처리 하는 방법을 사용할까 한다.


함수 포인터로 사용한 원형을 typedef로 선언한다.

typedef ngevent (*PF)(EVENT_INFO* arg);

이렇게 선언한 후에 일반 포인터로 사용할 경우는 아래와 같이 하면 된다.

PF pf; //pf에 함수 포인터 연결

vector을 사용할 경우에는 아래와 같이 사용한다.

//선언
vector<PF>  m_ClickEventHandler;

//연결할 함수를 작성한다.
ngevent test(EVENT_INFO* arg)
{
 return 1;
}

ngevent test2(EVENT_INFO* arg)
{
 return 1;
}

//vector 함수에 추가
m_ClickEventHandler.push_back(test);
m_ClickEventHandler.push_back(test2);

//함수를 vector의 배열로 for문을 통해서 호출한다.
for(int i = 0; i < (int)m_ClickEventHandler.size(); i++)
{
      EVENT_INFO info;
      info._click2d.x = 10.f * (float)i;
      m_ClickEventHandler[i](&info);
}


//////////////////////////////////////////////////

Posted by gsi
:

함수 포인터 타입 - (펌)

STL 2007. 9. 18. 14:48 |

주소 : http://www.winapi.co.kr/clec/cpp2/15-2-2.htm

함수 포인터 타입도 일종의 고유한 타입이다. 따라서 원형이 다른 함수 포인터끼리는 곧바로 대입할 수 없으며 함수의 인수로도 넘길 수 없다. 정수형 포인터 변수(int *)에 실수형 포인터 변수(double *)의 값을 대입할 수 없듯이 말이다. 다음 코드를 보자.

 

int (*pf1)(char *);

void (*pf2)(double);

pf1=pf2;                  // 타입이 다르므로 에러

 

pf1은 문자형 포인터를 인수로 취하고 정수형을 리턴하는 함수를 가리키는 함수 포인터이며 pf2는 실수를 인수로 취하고 리턴값이 없는 함수를 가리키는 함수 포인터이다. 두 변수가 가리킬 수 있는 함수의 원형이 다르기 때문에 pf2가 가리키는 번지를 pf1에 곧바로 대입할 수 없다. 만약 이것이 가능하다면 pf1로 함수를 호출할 때 컴파일러는 char *형의 인수를 찾지만 pf1이 가리키는 함수는 double형의 인수를 받아들이므로 불일치가 발생하며 함수가 제대로 호출되지 않을 것이다.

함수 포인터가 가리킬 수 있는 원형과 같지 않은 함수의 번지를 대입하는 것도 똑같은 이유로 에러로 처리된다. 다음 코드에서 pf3은 문자형 포인터와 실수를 인수로 취하고 리턴값이 없는 함수를 가리키도록 선언했는데 func 함수는 pf3의 원형과 다르므로 pf3에 func 함수의 번지를 대입할 수 없다.

 

int func(int a);

 

void (*pf3)(char *, double);

pf3=func;                         // 에러

 

그러나 타입이 다른 함수 포인터끼리라도 강제로 대입할 수는 있는데 이것이 일단은 가능해야 한다. void 포인터에 저장된 함수의 번지를 대입받는다거나 자료 구조 설계시에 미리 알 수 없는 함수에 대한 포인터를 다루고자 할 때이다. 이럴 때 사용하는 것이 바로 캐스트 연산자이며 여러 가지 이유로 강제 캐스팅의 필요성은 누구나 인정하고 있다. int *pi와 double *pd가 있을 때 pi=pd 대입은 금지되지만 pi=(int *)pd는 가능한 것처럼 함수 포인터도 타입에 맞게 캐스팅하면 강제로 대입할 수 있다.

데이터 포인터에서와 마찬가지로 함수 포인터에도 캐스트 연산자를 쓸 수 있는데 문제는 함수 포인터의 캐스트 연산자가 모양이 생소해서 조금 어렵다는 것이다. 함수 포인터는 타입 자체가 길기 때문에 캐스트 연산자의 모양도 상당히 복잡해 보인다. 다음 코드는 pf2를 pf1에 강제로 대입하기 위해 캐스트 연산자를 사용한 것이다.

 

int (*pf1)(char *);

void (*pf2)(double);

pf1=(int (*)(char *))pf2;

 

이 식에서 (int (*)(char *))가 캐스트 연산자이다. 함수 포인터형의 캐스트 연산자를 만드는 방법은 함수 포인터 선언식에서 변수명을 빼고 전체를 괄호로 한 번 더 싸주면 된다. 일종의 공식이므로 외워 두거나 아니면 필요할 때마다 이 공식을 찾아보기 바란다.

pf1=(int (*)(char *))pf2 대입문은 pf2가 가리키는 번지를 문자형 포인터를 인수로 취하고 정수를 리턴하는 함수 포인터 타입으로 잠시 바꾼 후 pf1에 대입한다. pf3에 func 함수의 번지를 강제로 대입할 때도 마찬가지로 캐스트 연산자를 사용할 수 있다. 물론 이렇게 강제로 대입했을 때의 부작용에 대해서는 스스로 책임져야 한다.

 

pf3=(void (*)(char *,double))func;

 

캐스트 연산자가 길어 보여서 그렇지 원리를 알고 나면 별로 어렵지 않다. 다음은 조금 이론적인 얘기가 되겠지만 함수 포인터의 배열이나 포인터를 선언하는 형식에 대해 알아보자. T형에 대해 T형 배열과 T형 포인터를 항상 선언할 수 있으므로 함수 포인터에 대해서도 배열과 포인터를 선언할 수 있다. func 타입의 함수를 가리킬 수 있는 함수 포인터를 요소로 가지는 크기 5의 arpf 배열은 다음과 같이 선언한다.

 

int (*arpf[5])(int);

 

함수 포인터 배열을 선언할 때는 변수명 다음에 첨자 크기를 밝혀 주면 된다. 잘못 생각하면 int (*arpf)(int)[5];가 맞을 것 같기도 한데 첨자 크기는 반드시 변수명 다음에 바로 써야 한다. 이 선언에 의해 int (*)(int)형의 함수의 번지를 가리킬 수 있는 함수 포인터 arpf[0] ~ arpf[4]까지 4개의 변수가 생성되며 각 변수는 int func(int)와 같은 원형의 함수를 가리키는 번지를 가질 수 있다. 동일한 타입의 변수들을 배열에 모아 두면 루프를 돌면서 함수들을 순서대로 호출한다거나 하는 처리도 가능해진다.

다음은 함수 포인터의 포인터를 선언해 보자. func 타입의 함수를 가리키는 함수 포인터를 가리키는 포인터 ppf는 다음과 같이 선언하는데 * 구두점만 하나 더 적으면 된다.

 

int (**ppf)(int);

 

이렇게 선언된 ppf는 int (*)(int) 타입으로 선언된 함수 포인터 변수나 함수 포인터 배열을 가리킬 수 있는 이차 함수 포인터 변수이다. ppf=&pf 또는 ppf=arpf 식으로 함수 포인터 변수의 번지를 대입받을 수 있으며 ppf로부터 함수를 호출할 때는 (**ppf)(2) 형식을 사용한다. 함수 포인터 배열 arpf와 이중 함수 포인터 ppf가 메모리에 구현된 모양은 다음과 같다.

함수 포인터의 타입은 함수가 취하는 인수들의 타입과 리턴값까지 정확하게 밝혀야 하기 때문에 타입의 형식이 너무 길어서 쓰기에 번거롭다. 또한 함수 포인터로부터 파생된 타입을 만드는 것도 헷갈리고 생소한 면이 있다. 그래서 함수 포인터 타입을 자주 사용하거나 자신이 없다면 직접 타입을 기술하는 것보다 typedef로 함수 포인터 타입을 따로 정의한 후 사용하는 것이 편리하다. int func(int)형의 함수를 가리키는 타입은 다음과 같이 정의한다.

 

typedef int (*PFTYPE)(int);

PFTYPE pf;

 

함수 포인터를 선언하는 문장에서 변수명을 원하는 타입 이름으로 바꾸고 앞에 typedef만 붙이면 된다. 이후 컴파일러는 PFTYPE이라는 명칭을 int (*)(int) 타입으로 인식하므로 PFTYPE으로 함수 포인터 변수를 쉽게 선언할 수 있으며 캐스트 연산자로도 사용할 수 있다. 또한 함수 포인터로부터 배열이나 포인터같은 파생 변수를 선언하는 것도 훨씬 더 간편하다.

 

PFTYPE arpf[5];

PFTYPE *ppf;

 

마치 int형으로부터 배열이나 포인터를 선언하듯이 PFTYPE을 사용할 수 있으므로 직관적이고 읽기에도 좋다.

Posted by gsi
:

STL 샘플 코드...강추!!!

STL 2007. 9. 18. 10:30 |

Posted by gsi
:

가끔 어이 없는 실수를 할때가 ^^..

stl::string 를 사용해서 문자열을 받는 곳에서 메모리 릭이 발생!!
아.. 어디지?.. 이게 왜 릭이 생기지?..

상속 구조를 취하게 되었을때 소멸자를 virtual로 해주어야 하는 것을 깜박 했다.

앞으로는 조심조심. ^^..
Posted by gsi
:

아래의 코드는 내가 정신없이 한줄을 작성하면서 생긴 일이다.
참으로 어이가 없는 경우이긴 하지만 발생할 수 있는 상태가 된 나로서는
아무래도 헤롱헤롱 하는 상태인듯 하다.

d:\NG_Project\Project\NGTools\NGMakerShop080\NGMakerShop080_Work\DataMgr\NGBObject.h(70): error C2039: 'first' : is not a member of 'std::_Tree<_Traits>::iterator'
        with
        [
            _Traits=std::_Tmap_traits<int,int,std::less<int>,std::allocator<std::pair<const int,int>>,false>
        ]

문제가된 코드

  map< int, int> m_test;
  m_test[10] = 10;
  map< int, int>::iterator iter = m_test.begin();
  int aaa = iter.first; //<--여기..

이 코드를 보고도 어디가 문제인지 모르는 분은 나랑 비슷한 상태인듯 하다 ^^

이 코드는 아래와 같이 되어야 한다.

int aaa = (*iter).first;

앞으로는 조금더 정신 차리고 해야 할거 같다.

Posted by gsi
:

stl string trim 구현하기

STL 2007. 9. 6. 14:43 |

string을 사용하고 있지만.. trim이 없는듯 합니다. -.- 혹시 알면 댓글.. 부탁 드림..

아래와 같은 프로그램 경로가 있다고 햇을때 프로그램 파일 부분만 잘라 낼려고 할대
아래와 같은 코드를 사용했습니다.

원본 패스 : d:\gsi_project\projectx\bin\AttachImageMakerd.exe
결과 패스 : d:\gsi_project\projectx\bin

//초기화

string appPath = argv[0];
string appdir;
appdir.clear();
//뒷 부분을 잘라 내야 하기 때문에 우선 뒤쪽에서 '\'를 찾는다.

int findidx = (int)appPath.rfind('\\');

//찾은 인덱스를 사용해서 잘라낸다.

appdir = string(appPath, 0, findidx); //appPath : 풀 패스, 0 : 시작인덱스, findidx : 끝 인덱스

이상...

Posted by gsi
:

float, int 등을 string 변환 - ostringstream 이용

#include <sstream>

std::ostringstream outstream;
outstream << 숫자등등
std::string str = outstream .str()

Posted by gsi
:

for_each()를 사용할때

//클래스

class Widget {
public:
 Widget(int var) : value(var) {}

 void Test() {
  cout << "값 " << value << endl;
 }

public:
 int value;
};

//함수 선언

void Test(Widget& w)
{
 cout << w.value << endl;
}

//사용하는곳

 vector<Widget> vw;

 vw.push_back(Widget(1));
 vw.push_back(Widget(2));
 vw.push_back(Widget(3));
 vw.push_back(Widget(4));
 vw.push_back(Widget(5));

//일반 함수는 Test 또는 ptr_fun(Test) 라고 하면 됩니다.

 for_each(vw.begin(), vw.end(), Test);
 for_each(vw.begin(), vw.end(), ptr_fun(Test));

//클래스 내부의 함수를 접근 할 때는 vw의 형태가 참조냐 포인터냐에 따라서

//달라 집니다. 참조 이기 때문에 mem_fun_ref(&Widget::Test)를 사용합니다.
 for_each(vw.begin(), vw.end(), mem_fun_ref(&Widget::Test));

 vector<Widget*> lpw;

 lpw.push_back(new Widget(1));
 lpw.push_back(new Widget(2));
 lpw.push_back(new Widget(3));
 lpw.push_back(new Widget(4));
 lpw.push_back(new Widget(5));

//포인터이기 때문에 mem_fun(&Widget::Test)를 사용하게 되지요.

 for_each(lpw.begin(), lpw.end(), mem_fun(&Widget::Test));

Posted by gsi
:

vector <> 에 포인터 객체를 넣게 되면 많은 부분 불편한게 생긴다.
메모리의 삭제에 있어서 다른 처리를 해야 하기 때문이다.

하지만 boost의 shared_ptr를 사용하면 아주 편하게 구현이 됩니다.
관련 내용 : http://crowmania.cafe24.com/crowmania/?p=50

[헤더]
#include <vector>
using namespace std;
#include <boost/shared_ptr.hpp>

//테스트할 클래스 구성
class CMemTest
{
public:
 CMemTest() : _val(0)
 {
 }
 CMemTest(int val)
 {
  _val = val;
 }
 ~CMemTest()
 {
 
 }

 int _val;
};

//부스터에 맞는 타입디파인
typedef boost::shared_ptr<CMemTest> SPMemTest;

[코드]
vector<SPMemTest> m_SPMemTest;

SPMemTest sp1 = SPMemTest(new CMemTest);
m_SPMemTest.push_back(sp1);
m_SPMemTest.push_back(sp1);
m_SPMemTest.pop_back();
m_SPMemTest.pop_back();

//이렇게 하면 삭제가 됩니다.
//다른 방법으로 사용하면 아래도 가능하죠
m_SPMemTest.push_back(SPMemTest(new CMemTest(10)));
m_SPMemTest.push_back(SPMemTest(new CMemTest));

//값을 사용할때
. 가 아니고 -> 를 사용해야 합니다.
m_SPMemTest[0]->_val = 10;

//erase와 clear만 사용하면 자동으로 메모리 삭제 됨

count = m_SPMemTest.size();
m_SPMemTest.erase(m_SPMemTest.begin());
count = m_SPMemTest.size();

m_SPMemTest.clear();

Posted by gsi
:

stl 문중에서 아마도 vector를 가장 개인적으로 선호 한다.
이론적인 내용은 우선 접어 두고.. (책을 보면 안다 ^^)

기존에 내가 했던 작업은 vector와 for문을 많이 사용했다.
이번에 accumulate, for_each를 공부 하면서 많은 부분 간소화 시키고
가독성과 범용성을 갖출수 있는 방법을 찾아 봤다.
class 의 객체를 vector에 추가 해서 작업 할때 vector의 배열 정보를 사용해서
특정 변수의 값을 다르게 변경할 작업이 많이 생긴다.

//헤더에 필요한 헤더파일을 추가한다.

#include <vector>
#include <map>
#include <algorithm>
#include <numeric>

using namespace std;

아래와 같은 클래스가 있다고 하자.

class Element {
public:
 DWORD UID;
 INT  Price;
 int  Count;
 DWORD Res_ID;

 //생성자
 Element(DWORD uid, INT price, int count, DWORD res_id, ) :
  UID(uid),
  Price(price),
  Count(count),
  Res_ID(res_id),
 {
 }

 //operator
 bool operator==(const Element& e) const {
  return (UID == e.UID) ? true : false;
 }
};

위의 코드에서 price는 가격을 뜻하고, count는 수량을 뜻한다.
Res_ID는 해당 오브젝트의 리소스 아이디라고 가정을 하자.
아래와 같은 작업을 할려고 한다.

1. Count가 음수인 요소들의 개수를 얻어 오고 싶다.
2. Count가 음수인 요소들의 Price의 총 합을 얻고 싶다.
3. Count가 음수인 요소들의 Res_ID의 목록을 얻고 싶다.

기존에 for문을 사용하게 되면 코드의 량도 늘어 나고 보기에도 좀 그렇다.
아래와 같은 accumulate 함수를 작성하고 활용하면 자연스럽게 구현이 가능하다.

//카운터가 0보다 작은 요소들의 개수
int count_minus_element_sum (int count, const Element& t1 ) {
 if(t1.Count < 0)
  count++;

 return count;
}

//카운터가 0보다 작은 요소들의 총금액
int count_minus_element_price_sum (int price, const Element& t1 )
{
 if(t1.Count < 0) {
  price += (abs(t1.Count) * t1.Price);
 }

 return price;
}

//카운터가 0보다 작은 resid를 추출
vector<DWORD>& count_minus_resid ( vector<DWORD>& v, const Element& t1 )
{
 if(t1.Count < 0) {
  v.push_back(t1.Res_ID);
 }
 return v;
}

//for_each - cout << resid << endl
void display_resid ( const DWORD& ri )
{
 cout << ri << endl;
}

//벡터 테스트
 vector< Element > m_ElementList;

//요소를 추가한다.

 m_ElementList.push_back(Element(100, 100, 1, 2000));
 m_ElementList.push_back(Element(101, 100, 2, 2001));
 m_ElementList.push_back(Element(102, 100, 3, 2002));
 m_ElementList.push_back(Element(103, 100, -1, 2003));
 m_ElementList.push_back(Element(104, 100, 0, 2004));
 m_ElementList.push_back(Element(105, 100, -2, 2005));
 m_ElementList.push_back(Element(106, 100, -3, 2006));
 m_ElementList.push_back(Element(107, 100, -1, 2007));
 m_ElementList.push_back(Element(108, 100, 2, 2008));
 m_ElementList.push_back(Element(109, 100, 3, 2009));
 m_ElementList.push_back(Element(110, 100, 6, 2010));

//음수인 요소의 개수의 총 합을 구한다.

 int count = accumulate(m_ElementList.begin(), m_ElementList.end(), 0, count_minus_element_sum);

//음수인 요소의 가격의 총 합을 구한다.
 int price = accumulate(m_ElementList.begin(), m_ElementList.end(), 0, count_minus_element_price_sum);

//음수인 요소의 Res_ID의 목록을 구한다.
 vector<DWORD> m_ResID; //목록을 담을 배열을 선언한다.
 m_ResID.clear(); //클리어
 m_ResID = accumulate(m_ElementList.begin(), m_ElementList.end(), m_ResID, count_minus_resid);

//담겨진 요소의 Res_ID를 화면에 출력해 본다.

 for_each(m_ResID.begin(), m_ResID.end(), display_resid);

위와 같이 accumulator를 잘만 사용하면 아주 다양한 효과를 볼 수 있을거 같다.
총 합을 구하거나 모든 요소의 특징을 살펴 본다거나 하는 형태의 작업에 아주 탁월하다.

for_each는 for문을 사용하는 번거로움을 조금 해소해 줄수 있다.

Posted by gsi
:

vector 라는 컨테이너 다른 경우도 포함이 되지만. 컨테이너는 지능적이기는 하지만 메모리에 대해서는 신경을 쓰지 않습니다. 즉 new로 선언한 객체의 delete가 행해 지지 않는 다는 거죠.

보통 아래의 일반적인 경우로 메모리를 처리 할수 있습니다.

//헤더 선언

#include <vector>
#include <functional> -> 아래쪽 디파인 잡을때 사용되는거
#include <algorithm> -> 아래쪽 디파인 잡을때 사용되는거
#include <iostream>

using namespace std;

//선언

 vector< int* > m_List;

//추가

 m_List.clear();

 for(int i = 0; i < 2; i++) {
  int* p = new int;
  *p = 10;
  m_List.push_back(p);
 }

//삭제

 for(vector< int* >::iterator i = m_List.begin(); i != m_List.end(); ++i)
 {
  delete (*i);
 }

// 조금 편한 삭제 방법

//디파인

class DeleteObj
{
public:
 template<typename T>
 void operator()(const T* ptr) const
 {
  delete ptr;
 }
};

//삭제

for_each(m_List.begin(), m_List.end(), DeleteObj());

위의 클래스로 템플릿을 만들어 놨기 때문에.
대부분의 객체에 삭제 함수로 적용할 수 있다.
for_each를 통해서 조금더 코드량을 줄이고 가독성을 높일수 있을거 같다.

Posted by gsi
:

vector과 string의 용법

STL 2007. 9. 6. 14:37 |

//vector

void doSomething(const int* pInts, size_t numInts) {}

int의 배열정보를 가져 올때 아래와 같이

doSomething(&v[0], v.size());

v가 빈 디렉토리일때 &v[0]가 잘못된 값을 가져 올수 있기
때문에 아래 표기가 맞습니다.

if(!v.empty()) {
   doSomething(&v[0], v.size());
}

** &v[0] == &*v.begin()

//string

void doSomething(const char *pString) {}

string로 부터 char*를 가져 올때 아래와 같이

doSomething(s.c_str());

C API : 이 함수는 최대 arraySize 만큼의 double을 가진 배열에 대한 포인터를 받아 그 배열에 데이터를 기록 합니다. 동작이 끝나고 나면 데이터가 기록된 double의 개수를 반환하는데, 이 값은 maxNumDoubles를 넘지 않습니다.

size_t fillArray(double *pArray, size_t arraySize);

크기가 maxNumDoubles인 벡터를 생성합니다.

vector<double> vd(maxNumDoubles);

fillArray를 써서 vd에 데이터를 기록하고, resize를 써서 vd의 크기를 fillArray가 반환한 수치로 맞춥니다.

vd.resize(fillArray(&vd[0], vd.size());

C API : 이 함수는 최대 arraySize 만큼의  char를 가진 배열에 대한 포인터를 받아 그 배열에 데이터를 기록합니다. 동작이 끝나고 나면 데이터가 기록된 char의 개수를 반환하는데, 이 값은 maxNumChars를 넘지 않습니다.

size_t fillString(char *pArray, size_t arraySize);

maxNumCahrs 만큼의 크기를 가진 벡터를 생성합니다.

vector<char> vc(maxNumChars);

fillString을 써서 vc에 데이터를 기록합니다.

Size_t charsWritten = fillString(&vc[0], vc.size());

vc에 s로 데이터를 복사하는데, 이때 범위 생성자를 사용합니다.

stirng s(vc.begin(), vc.begin() + charsWritten);

쓸데 없이 남은 용량 없애기 (vector)

vector가 100,000개인 데이터를 추가한 후에 10개의 데이터만을 남기가 모두 erase로 했다고 가정해 봅시다. 이때 vector는 10개의 데이터를 가지고 있지만 내부적으로는 100,000개의 데이터 공간이 존재 하게 됩니다. 즉, 불필요한 용량이 존재 하게 됩니다.

이때 swap를 사용해서 용량을 현재 크기에 맞게 설정할 수 있습니다.

vector<Contestant>(contestant).swap(contestant);

vector< Contestant>( contestant) 이 표현식은 contestant의 사본인 임시 벡터 객체를 만듭니다. 즉, vector의 복사 생성자가 contestant의 상수 참조자를 매게변수로 받아 동작하는 거죠, 단, 이 복사 생성자는 요소가 복사되는데 필요한 만큼의 메모리만을 할당하기 때문에, 이렇게 만들어지는 객체는 contestant와 달리 딱 맞는 용량이 잡혀 있게 됩니다.

그 다음 swap 문이 이어 지는데요. 이 함수에 의해서 임시 벡터 안의 데이터와 contestant안의 데이터가 완전히 싹 바뀝니다.

이렇게 되면 용량이 현재 사이즈에 맞게 수축됩니다.

swap를 거치게 되면서 데이터의 반복자, 포인터, 참조자는 그대로 유지됩니다.

Posted by gsi
:

stl vector sort

STL 2007. 9. 6. 14:36 |

#include <vector>
#include <algorithm>

using namespace std;

bool compare(type a,type b)
{
  return a>b(비교);  
}

void function()
{
  vector<type> v;
  sort(v.begin(),v.end(),compare) ;
}

Posted by gsi
:

for_each 에 대해서...(이펙티브 STL 내용 발췌.. 243 페이지)

이 알고리즘은 범위 내의 데이터를 요약할 수 있는 또 하나의 알고리즘이면서 accumulate가 가진 이상한 제한도 받지 않습니다. for_each는 범위와 그 범위 내의 요소에 대해 호출할 함수(대개 함수 객체)를 받아 들이는데, 이 알고리즘에 넘겨지는 함수는 자신이 처리할 단 하나의 요소만을 받아들이며, for_each는 자신의 수행을 마칠 때 이 함수를 반환합니다(엄밀히 말하면 그 함수의 사본(copy) 입니다.  항목 38에서 더 자세히 공부하세요). 가장 중요한 포인트는 for_each에 넘겨지는 (그리고 반환되는) 함수는 부가적 효과를 가져도 된다는 것입니다.

부가적 효과에 대한 사항을 차지하고라도, for_each는 두 가지 면에서 accumulate와 다릅니다. 우선 accumulate라는 이름 자체에서 "범위를 요약한다"는 느낌이 강하게 풍겨집니다. for_each는 "범위 내의 모든 요소에 어떤 일을 한다"라는 냄새가 나죠. 물론 이 알고리즘들의 일차적인 목적이 그것이겠지만요. 어쨌든 for_each를 써서도 범위를 요약할 수 있습니다. 하지만 accumulate처럼 확실하지 않다는 것 뿐이죠.

두번째, accumulate는 우리가 원하는 요약 결과를 바로 반환하지만, for_each는 자신이 매게 변수로 받은 함수 객체를 반환하기 때문에 이 객체에서 요약 정보를 뽑아내야 합니다. C++ 업에 용어로 말하면 for_each에 넘기는 함수자 객체에다가 요약 정보를 얻어 낼 수 있는 멤버 함수를 추가해야 한다는 의미이지요.

.. 이상..

대부분 vector의 예를 보면 간단하게 아래와 같이 서술할 겁니다.

class CTest
{
public:
  CTest() {}
  ~CTest() {}

private:
  ... 내용...
};

void Test(CTest& e) { ... 내용... }

vector<CTest> m_vTest;

//배열의 정보를 사용해서 Test() 함수를 실행할려고 할때.

vector<CTest>::iterator iter;
for(iter = m_vTest.Begin(); iter != m_vTest.End(); iter++) {
  Test((*iter));
}

//이런 형태로 구성하게 되지요.
//하지만 for_each를 구성하면 한줄로 심플하게 구성됩니다.

std::for_each(m_vTest.Begin(), m_vTest.End(), &Test);

//이렇게 한줄로 요약이 되는군요.
//여기서 조금더 확장해서  Test() 함수에 템플릿을 연동하면
//비슷한 형태의 다른 타입의 vector로 선언된 변수들을 연동할수 있습니다.

template < class T >
void Test(T& e) { ... 내용 ... }
std::for_each(m_vTest.Begin(), m_vTest.End(), &Test);

//이렇게만 구성하면 컴파일 오류가 납니다.
//아래와 같이 구성하시면 됩니다.

std::for_each(m_vTest.Begin(), m_vTest.End(), &Test<CTest>);

위의 코드는 오류가 있을지도 모릅니다. 제 나름대로 정리해본겁니다.
하지만 위의 코드가 더 다양한 방법으로 전환되기도 하더군요.
예를 들어서 CTest 클래스 내부에 Test() 함수를 넣고 그것을 for_each에 연동할 수 있더라구요.
Exceptional C++ Style 책에 보니 내용이 있더라구요.
아래와 같은 코드로 사용하면 되는듯 합니다.

std::for_each(m_vTest.Begin(), m_vTest.End(), std::mem_fun_ref( &CTest::Test));

이렇게 구성하시면 됩니다.
아 그리고 for_each는 Test가 반환되는 값이 있다면 앞쪽에 붙여서 받으면 되요.

Posted by gsi
: