앞에까지는 STL의 알고리즘에 추가된 것들을 다루었는데 이번에는 컨테이너 하나를 소개하겠습니다사실 이 컨테이너는 저도 얼마 전까지만 하더라도 새로 추가 된지 몰랐습니다.^^;

 

새로 추가된 컨테이너의 이름은 forward_list입니다.

이름을 들어보니 대충 어떤 컨테이너인지 감이 오시죠?^^ 네 이 컨테이너는 기존의 list 컨테이너와 비슷한 종류의 컨테이너입니다.

 

 

forward_list를 만든 이유

표준 라이브러리(STL)에는 이미 리스트(std::list) 라이브러리가 있습니다이것은 쌍 방향 리스트입니다. list는 사용하기는 편하지만 사용 메모리나 처리 속도에 조금 아쉬운 점이 있습니다또 대 부분의 상황에서 쌍 방향 리스트가 필요한 경우보다는 단 방향 리스트만으로 충분한 경우가 자주 있습니다이런 이유로C++0x에서는 단 방향 리스트를 추가하기로 했습니다.

 

 

forward_list의 설계 방침

1. 특별한 이유가 없다면 forward_list는 기존의 list의 설계에 맞춘다.

2. 설계 상의 선택 기가 여러 개인 경우 성능(속도와 사이즈)을 최우선 한다(C의 구조체로 구현하는 경우와 비교하여 Zero Overhead로 한다).

3. std::list insert erase를 forward_list에서도 제공할 수 있지만 구현이 복잡해지고 성능 측면에서 좋지 않으므로 제공하지 않는다.

4. 다른 STL의 컨테이너들에 있는 size 함수를 제공하지 않는다이유는 요소 수를 보존하는 멤버를가지고 있으면 C언어에서 구현한 것과 비교해서 불필요한 메모리를 사용한다. 만약 이런 멤버를 가지고 있지 않으면서 size 함수를 지원하면 호출할 때마다 모든 요소를 세어야 하므로 계산량이 O(N)이 된다(그런데 유저는 다른 컨테이너와 같이 size의 계산량이 작을 것이라고 생각할 수 있다). 또 이미 unordered와 같은 연상 컨테이너도 기존의 요소를 만족하지 않고 있다.

  

 

STL list 컨테이너와 다른 점

forward_list는 기존의 list와 아래와 같은 점이 다릅니다.

1. forward_list는 단 방향 리스트(singly-linked-list)이다각 요소는 그 다음 요소를 가리키는 포인터를 하나만 가지고 있다(list은 양 방향 리스트).

2. (단 방향 리스트이므로) list에 비해서 메모리를 작게 사용한다이것은 각 요소의 메모리만이 아닌 컨테이너 그 자체의 사이즈도 작다. int 형에 대해서 list 12바이트라면 forward_list 8바이트이다(64비트에서는 각각 24, 16).

3. list에 비해 삽입/삭제 속도가 더 빠르지만 그 차이는 크지는 않다

4. 한 방향으로만 이동할 수 있다.

5. 삽입과 삭제는 지정한 요소의 다음 요소만 가능하다.

 

 

forward_list의 멤버 리스트

기능

멤버

대입

assign

반복자

befor_begin

 

cbefore_begin

 

begin

 

end

 

cbegin

 

cend

비었는지 조사

empty

현재 크기(size)

지원 안함

사이즈 변경

resize

모두 삭제

clear

선두에 추가

push_front

선두 요소 삭제

pop_front

선두 요소 참조

front

삽입

insert_after

삭제

erase_after

조건 삭제

remove

 

remove_if

중복 요소 삭제

unique

교환

swap

병합

merge

정렬

sort

반전

reverse

 


STL의 컨테이너를 사용해보았다면 forward_list라고 해서 딱히 어려운 부분은 없습니다다만 forward_list이 단 방향 리스트라는 것과 다른 컨테이너에서는 지원하는 기능이 일부 없다는 것을 잘 숙지해야 합니다.

 

필요한 헤더 파일

forward_list는 이름과 같은 ‘forward_list’라는 헤더 파일을 포함해야 합니다.

#include <forward_list>

 

 

[예제] forward_list를 사용하여 요소 추가순회삭제하기

#include "stdafx.h"

#include <iostream>

#include <forward_list>

 

using namespace std;

 

 

int main()

{

           forward_list< int > flist;

 

 

           cout << "flist에 추가한 요소들 출력" << endl;

           // 추가하기

           auto iter = flist.before_begin();

           for( int i = 0; i < 5; ++i )

           {

                     iter = flist.insert_after( iter, i );

           }

                    

           // 순회

           for( iter = flist.begin(); iter != flist.end(); ++iter )

           {

                     cout << *iter << endl;

           }

 

           cout << endl;

           cout << "flist의 요소들 중 일부를 삭제한 후 남은 요소들 출력" << endl;

           // 순회 하면서 일부 요소 삭제

           auto prev_iter = flist.before_begin();

           iter = flist.begin();

           while( iter != flist.end() )

           {

                     if( 3 == *iter )

                     {

                                iter = flist.erase_after( prev_iter );

                                continue;

                     }

                     ++prev_iter;

                     ++iter;

           }

 

           // 순회

           for( iter = flist.begin(); iter != flist.end(); ++iter )

           {

                     cout << *iter << endl;

           }

 

           return 0;

}

 

결과 >


 

위 예제를 보면 아시겠지만 forward_list std::list에 비해 성능 면의 이점을 가지고 있지만 사용 측면에서는 조금 불편한 점이 좀 있습니다그러나 C와 비슷한 성능을 내고 싶은 경우에는 좋은 선택 기가 될 수도 있습니다.

 


참고

http://msdn.microsoft.com/ko-kr/library/ee373568.aspx

저작자 표시
신고
by 흥배 2012.09.14 09:00

C++03까지의 STL에는 데이터셋에서 가장 작은 요소를 찾을 때는 min_element, 가장 큰 요소를 찾을 때는max_element를 사용하였습니다.

그런데 만약 최소와 최대를 동시에 찾을 때는 어쩔 수 없이 min_element max_element를 각각 호출해야 하는 불필요한 불편한 점이 있었습니다.

 

C++0x에서는 이런 불편함을 개선하기 위해 한번에 최소와 최고를 찾아주는 minmax_element 알고리즘이 새로 생겼습니다.

 

 

minmax_element

template<class ForwardIterator>

    pair< ForwardIterator, ForwardIterator >

        minmax_element( ForwardIterator _First, ForwardIterator _Last );

template<class ForwardIterator, class BinaryPredicate>

    pair< ForwardIterator, ForwardIterator >

        minmax_element( ForwardIterator _First, ForwardIterator _Last, BinaryPredicate _Comp );

 

minmax_element 알고리즘에는 조건자를 사용하는 버전과 조건자를 사용하지 않은 버전 두 가지가 있습니다데이터셋의 자료형이 유저 정의형(class struct를 사용한)이라면 조건자가 있는 버전을 사용합니다.

 

예제 코드 >

#include <iostream>

#include <algorithm>

using namespace std;

 

 

int main()

{

           int Numbers[10] = { 50, 25, 20, 7, 15, 7, 10, 2, 1, 3 };

          

           pair<int*, int*> MinMaxValue = minmax_element( &Numbers[0], &Numbers[10] );

 

           cout << "최소 값 : " << *MinMaxValue.first << endl;

           cout << "최대 값 : " << *MinMaxValue.second << endl;

          

           return 0;

}

 

결과 >


 

저작자 표시
신고
by 흥배 2012.09.06 09:30

데이터셋을 시퀸스(연속적인)한 값으로 채우고 싶을 때는 iota 알고리즘을 사용합니다.

앞서 소개한 알고리즘들은 <algorithm> 헤더 파일에 정의 되어 있는 것에 반해 iota 알고리즘은<numeric> 헤더 파일에 정의 되어 있습니다.

 

itoa

template<class ForwardIterator, class T>

  void iota(ForwardIterator first, ForwardIterator last, T value);

 

 

아래는 예제 코드와 결과 입니다.

#include <iostream>

#include <vector>

#include <numeric>

using namespace std;

 

int main()

{

           vector<int> Numberlist;

           Numberlist.push_back( 2 );

           Numberlist.push_back( 5 );

           Numberlist.push_back( 7 );

           iota( Numberlist.begin(), Numberlist.end(), 2 );

 

           for( auto IterPos = Numberlist.begin(); IterPos != Numberlist.end(); ++IterPos )

           {

                     cout << *IterPos << endl;

           }

 

           return 0;

}

 

결과 >

 

위 예제를 보면 아시겠지만 iota의 세 번째 인자의 값이 시작 값이고, 이후에 값이 하나씩 증가합니다.

저작자 표시
신고
by 흥배 2012.09.06 09:00

is_heap is_heap_until는 앞서 소개했던 is_sorted, is_sorted_until과 비슷한 알고리즘입니다차이가 있다면is_heap is_heap_until는 정렬이 아닌 Heap을 다룬다는 것만 다릅니다.

 

is_heap은 데이터셋이 Heap으로 되어 있는지 아닌지, is_heap_until는 데이터셋에서 Heap이 아닌 요소의 첫 번째 위치를 반환합니다.

 

is_heap

template<class RandomAccessIterator>

    bool is_heap(

        RandomAccessIterator _First,

        RandomAccessIterator _Last

    );

template<class RandomAccessIterator, class BinaryPredicate>

    bool is_heap(

        RandomAccessIterator _First,

        RandomAccessIterator _Last,

        BinaryPredicate _Comp

    ); 

 

 

is_heap_until

template<class RandomAccessIterator>

    bool is_heap_until(

        RandomAccessIterator _First,

        RandomAccessIterator _Last

);

template<class RandomAccessIterator, class BinaryPredicate>

    bool is_heap_until(

        RandomAccessIterator _First,

        RandomAccessIterator _Last,

        BinaryPredicate _Comp

);

 

 

is_heap is_heap_until는 각각 조건자를 사용하는 버전과 사용하지 않는 버전 두 개가 있습니다조건자를 사용하지 않는 경우는 operator< 를 사용합니다.

 

 

그럼 is_heap is_heap_until을 사용한 아주 간단한 예제 코드를 봐 주세요^^

#include <iostream>

#include <algorithm>

using namespace std;

 

 

int main()

{

           int Numbers1[10] = { 50, 25, 20, 7, 15, 7, 10, 2, 1, 3 };

           int Numbers2[10] = { 50, 25, 20, 7, 15, 7, 10, 6, 11, 3 };

           int Numbers3[10] = { 50, 25, 20, 7, 15, 16, 12, 3, 6, 11 };

          

          

           bool IsResult = false;

           IsResult = is_heap( &Numbers1[0], &Numbers1[10], [](int x, int y) { return x < y; } );

           cout << "Numbers1 Heap인가 ? " << IsResult << endl;

 

           IsResult = is_heap( &Numbers2[0], &Numbers2[10], [](int x, int y) { return x < y; } );

           cout << "Numbers2 Heap인가 ? " << IsResult << endl;

 

           IsResult = is_heap( &Numbers3[0], &Numbers3[10] );

           cout << "Numbers3 Heap인가 ? " << IsResult << endl;

 

           cout << endl;

           int* NumIter = is_heap_until( &Numbers2[0], &Numbers2[10], [](int x, int y) { return x < y; } );

           cout << "Numbers2에서 Heap되지 않은 첫 번째 위치의 값 : " << *NumIter << endl;

 

           return 0;

}

 

< 결과 >

 

 

 

ps : 자료구조 Heap에 대해서 잘 모르시는 분들은 아래의 글을 참고해 주세요

http://blog.naver.com/ctpoyou/105423523

저작자 표시
신고
by 흥배 2012.09.05 19:30

is_sorted는 데이터셋이(컨테이너나 배열정렬되어 있다면 true를 반환하고그렇지 않다면 false를 반환 합니다.

is_sorted_until는 데이터셋에서 정렬되어 있지 않는 요소의 첫 번째 위치를 반환합니다.

 

is_sorted와 is_sorted_until의 원형은 아래와 같습니다.

is_sorted

template<class ForwardIterator>

    bool is_sorted( ForwardIterator _First, ForwardIterator _Last );


template<class ForwardIterator, class BinaryPredicate>

    bool is_sorted( ForwardIterator _First, ForwardIterator _Last, BinaryPredicate _Comp );

 

 

is_sorted_until

template<class ForwardIterator>

    ForwardIterator is_sorted_until( ForwardIterator _First, ForwardIterator _Last);

 

template<class ForwardIterator, class BinaryPredicate>

    ForwardIterator is_sorted_until( ForwardIterator _First, ForwardIterator _Last,

               BinaryPredicate _Comp );

 

위의 is_sorted와 is_sorted_until의 원형을 보시면 알겠지만 조건자(함수객체)를 사용하는 버전과 사용하지 않는 버전 두 가지가 있습니다.

조건자를 사용하지 않는 경우 기본으로 operator<가 적용됩니다.

 

프로그래머는 코드로 이해하죠? ^^ 그럼 바로 예제 코드 들어갑니다.

이번 예제는 간단하게 만들기 위해 정수 배열을 사용해 보았습니다아마 STL을 이제 막 공부하고 있는 분들은 알고리즘을 STL의 컨테이너에만 사용할 수 있는 것으로 알고 있는 분들도 있을텐데 그렇지 않습니다.아래 예제는 int 형 배열을 사용하였습니다.

 

예제 코드 >

#include <iostream>

#include <algorithm>

using namespace std;

 

 

int main()

{

           int Numbers1[5] = { 1, 2, 3, 4, 5 };

           int Numbers2[5] = { 5, 4, 3, 2, 1 };

           int Numbers3[5] = { 1, 2, 4, 3, 5 };

           bool IsResult = false;

 

          

           IsResult = is_sorted( &Numbers1[0], &Numbers1[5], [](int x, int y) { return x < y; } );

           cout << "Numbers1. 오름 차순 ? " << IsResult << endl;

 

           IsResult = is_sorted( &Numbers2[0], &Numbers2[5], [](int x, int y) { return x > y; } );

           cout << "Numbers2. 내림 차순 ? " << IsResult << endl;

 

           IsResult = is_sorted( &Numbers3[0], &Numbers3[5], [](int x, int y) { return x < y; } );

           cout << "Numbers3. 오름 차순 ? " << IsResult << endl;

 

           cout << endl;

           cout << "is_sorted에서 조건자(함수객체)를 생략한 경우 " << IsResult << endl;

           IsResult = is_sorted( &Numbers1[0], &Numbers1[5] );

           cout << "Numbers1 is_sorted의 결과는 ? " << IsResult << endl;

           IsResult = is_sorted( &Numbers2[0], &Numbers2[5] );

           cout << "Numbers2 is_sorted의 결과는 ? " << IsResult << endl;

 

           cout << endl;

           int Numbers4[8] = { 1, 2, 3, 5, 4, 5, 7, 8 };

           int* NumIter = is_sorted_until( &Numbers4[0], &Numbers4[5], [](int x, int y) { return x < y; } );

           cout << "Numbers4에서 정렬되지 않은 첫 번째 위치의 값 : " << *NumIter << endl;

 

           return 0;

}

 

결과 >


 

저작자 표시
신고
by 흥배 2012.09.05 19:28

VC10에서 선보였던 C++11의 기능 중 강력하면서 사용하기 쉽고, 자주 사용한 기능이 아마 'auto'이지 않을까 생각합니다. 예전에 강연을 할 때 auto와 관련된 예제를 보여드리면 많은 분들이 아주 좋아하시더군요(좀 놀라기도 하시더군요^^). 어떤 분들은 딴 건 제쳐두고 이것 때문이라도 VC10을 사용해야겠다는 분들이 있었습니다.

 

이번 VC11에서도 'auto'와 같은 강력한 기능이 있습니다. 바로 'range base for' 입니다. 이것을 사용하면 반복문을 아주 쉽고, 강력하게 사용할 수 있습니다.

VC 특화 기능인 for each와 비슷하기 때문에 기존에 for each를 사용하고 있다면 이제는 range base for로 쉽게 바꾸어서 사용하면 됩니다.

 

 

예제를 통해 일반적인 for , VC for each, range base for문의 차이를 예제를 통해서 보겠습니다.

 

< 예제. 1 >

#include <iostream>

  

int main()

{

           int NumberList[5] = { 1, 2, 3, 4, 5 };

 

          

           std::cout << "일반적인 for " << std::endl;

          

           for( int i = 0; i < 5; ++i )

           {

                     std::cout << i << std::endl;

           }

 

 

           std::cout << "VC++ 특화의 for each" << std::endl;

 

           for each( int i in NumberList )

           {

                     std::cout << i << std::endl;

           }

 

 

           std::cout << "range base for " << std::endl;

 

           for( auto i : NumberList )

           {

                     std::cout << i << std::endl;

           }

 

           return 0;

}

 


< 실행 결과 >


 


<예제.1>을 보면 일반적인 for 문은

for( int i = 0; i < 5; ++i )

와 같이 시작과 종료 조건, 증가 값 이렇게 3개의 조건에 의해서 반복 됩니다.

 

그러나 range base for문은 VC만의 반복문인 for each와 비슷하게 데이터셋 변수와 이 데이터셋 요소의 타입을 선언하면 됩니다.

for( auto i : NumberList )

 

기존의 for 문에 비해서 또는 for each 보다도 간편해졌고, for each는 표준이 아닌 VC만의 기능인 것에 비해서 range base for C++ 표준 기능입니다.

 

range base for 문의 문법은 아래와 같습니다.

for ( for-range-declaration : expression ) statement

 

 

range base for 덕분에 반복문의 사용이 쉬워졌고, for 문을 사용할 때 종료 조건이 잘못되어 메모리 침범을 하는 위험도 피할 수 있게 되었습니다.

저작자 표시
신고
by 흥배 2012.08.29 09:00

Placement Insert C++11의 기능 중에 하나로 STL 컨테이너와 관계가 있습니다.

VC11 Placement Insert를 지원합니다. 만약 이 기능을 VC10 이하에서 사용하고 싶다면 Boost 라이브러리의 컨테이너를 사용하면 됩니다. 


struct ITEM

{

ITEM( int nCode )

{

}

};

 

std::vector< ITEM > Items;

 

Items.push_back( ITEM( 1 ) );

 

 

현재까지는 위 코드처럼 ITEM이라는 객체를 Items 컨테이너에 생성과 동시에 추가를 할 때는 위와 같이해야 합니다. 그런데 위 방식으로 하면 추가를 위해 컨테이너에 한번 생성을 한 후 복사를 해야 하는 문제가 발생합니다(또 임시 객체 만들므로 삭제 비용도 발생합니다).

 

이와 같은 동작은 우리가 원하는 것이 아닙니다.

 

그래서 C++11에서는 이와 같은 문제를 해결했습니다. 바로 ‘Placement Insert’가 해결했습니다.

 

C++11 ‘Placement Insert’를 사용하면 위의 코드는 아래와 같이 할 수 있습니다.

 

std::vector< ITEM > Items;

 

Items.emplace_back( 1 );

 

emplace_back push_back과 같지만 Placement Insert 기능이 구현된 것으로 임시 오브젝트를 만들면서 발생하는 비용을 없애줍니다.

 

C++11의 각 컨테이너에는 Placement Insert와 관련된 멤버로

emplace(insert),

emplace_back(push_back),

emplace_front(push_front),

emplace_hint(insert. 연관 컨테이너 용)

가 추가됩니다.

 

Placement Insert C++11의 새로운 기능인 가변 인수 템플릿을 사용하여 구현되었습니다.

 


Placement Insert는 아래와 같은 주의할 점도 있습니다.

 

1. explicit 문제.

   explicit 생성자도 암묵적으로 호출됩니다.

 

2. "0" 문제.

생성자의 파라미터가 포인터인 경우 인자로 0을 넘기면 int로 추론합니다. 그래서 이 경우에는 nullptr을 사용해야 합니다.

저작자 표시
신고
by 흥배 2012.08.27 09:00

Node.js 코드를 Windows에서 직접 빌드하기 위해서는 소스 코드에서 VC++ 프로젝트 파일을 생성해야 합니다.


Node.js의 빌드 시스템은 파이썬의 gyp 형식을 사용합니다. 그래서 먼저 파이썬 2.7 버전이 설치 되어 있어야 합니다.



1. http://www.nodejs.org 에서 소스 코드 다운로드 후 압축 풀기


2. (설치 되어 있지 않다면)파이썬 2.7 버전 설치. 환경설정에서 Path에 등록하기


3. 콘솔 창을 실행한 후 Node.js 소스가 있는 곳에서(여기서는 node-v0.8.5)에서 vcbuild.bat 실행




4. node-v0.8.5/tools/gyp/tools 디렉토리에서 pretty_sln.py 실행




5. node-v0.8.5 디렉토리에 솔루션 파일이 생성됨





ps : 그런데 아직 VS2012에서 직접 빌드는 해보지 않았습니다^^;


2012.08.24 : 0.8.8 버전 소스를 받아보니 위에서 3번까지만 하면 프로젝트 파일과 빌드까지 다 해줍니다.^^

저작자 표시
신고
by 흥배 2012.08.23 09:00

VC11 STL 컨테이너들은 이전 버전에 비해서 크기가 작아져서 메모리를 절약할 수 있게 되었습니다. 이전 버전과 다르게 VC11부터는 데스크탑 뿐만이 아닌 테블렛이나 스마트폰의 모바일 플랫폼 개발에서도 사용되므로 메모리 절약은 적지 않은 도움이 되리라 생각합니다.

 

아래 표는 x86(32비트 또는 ARM) x64(64비트) 플랫폼에서 각 VC 버전 별로 얼마만큼의 메모리를 사용하는 잘 표시하고 있습니다.

 

이 표는 VC11 뿐만이 아닌 이전 버전 사용자들에게도 도움이 될 것 같습니다. 저와 같은 서버 프로그래머들은 서버 프로그램이 설정한 동접자 수에서 어느 정도의 메모리를 소비할지 어느 정도 계산하고 있어야 하는데 이 표를 보면 메모리 계산할 때 도움이 될 것입니다

 

표의 바이트 사이즈는 Release 버전 기준입니다. 표에서 'VC9 SP1 SCL=0'SCL _SECURE_SCL를 뜻하는 것으로 원래 SCL은 기본은 1인데, 최고 스피드를 위해서 수동으로 SCL0으로 설정한 것입니다. VC10 VC11에서는 기본으로 _SECURE_SCL 0으로 되어 있습니다.

 


표의 출처는 MSDN입니다^^




저작자 표시
신고
by 흥배 2012.07.12 09:00

예전에 Visual C++ 10과 관련된 책을 집필할 계획이 있어서 그때 작성한 글인데 책 출간 계획이 사라졌으므로(한참 전에)

그냥 공개합니다. 글은 초보자를 타겟으로 하고 있으며 Visula C++ 10의 디버깅 기능을 설명하고 있습니다.


도움이 되었으면 좋겠습니다^^



6장 디버깅.pdf


저작자 표시
신고
by 흥배 2012.04.23 09:00
| 1 2 3 4 5 |

티스토리 툴바