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
:

화면에 보여지는 객체로 여기지 않고 Resource로 처리 하면서
화면의 다른 객체에 표현 가능하게 할려면 아래와 같은 코드로 변형 하면 됩니다.
이때 Grid의 x:Key 가 부여 되어야 합니다. ^^

 <Window.Resources>
  <Grid x:Key="KTestGrid" HorizontalAlignment="Left" Margin="38.857,8,0,0" x:Name="TestGrid" VerticalAlignment="Top" Width="151.786" Height="126.286">
   <Rectangle Margin="19.643,20.929,28.572,30.357" Stroke="#FF000000">
    <Rectangle.Fill>
     <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
      <GradientStop Color="#FFFF3838" Offset="0"/>
      <GradientStop Color="#FFFFFFFF" Offset="1"/>
     </LinearGradientBrush>
    </Rectangle.Fill>
   </Rectangle>
  </Grid>
 </Window.Resources>
Posted by gsi
: