Search

'흥배'에 해당되는 글 49건

  1. 2012.06.25 [ VC11 ] 대격변(?) Visual C++ 11 (3)
  2. 2012.02.27 [미리 보는 C++11] 8. Placement Insert
  3. 2011.09.23 [미리 보는 C++11] 4. constexpr - 2
  4. 2011.09.15 [미리 보는 C++11] 3. constexpr - 1 (1)
  5. 2011.08.30 [미리 보는 C++11] 2. override와 final (4)
  6. 2011.08.22 [미리 보는 C++11] 1. UTF-8, UTF-16(char_16t), UTF-32(char32_t) 문자형 (7)
  7. 2011.06.21 [STL] 15. VC++ 10에 추가된 새로운 컨테이너 forward_list – 사용편
  8. 2011.06.14 [STL] 14. VC++ 10에 추가된 새로운 컨테이너 forward_list – 소개편 (1)
  9. 2011.05.30 [STL] 13. <algorithm>에 추가된 새로운 함수들 minmax_element
  10. 2011.05.19 [STL] 12. <algorithm>에 추가된 새로운 함수들 iota
  11. 2011.05.11 [STL] 11. <algorithm>에 추가된 새로운 함수들 is_heap, is_heap_until
  12. 2011.04.25 [STL] 10. <algorithm>에 추가된 새로운 함수들 is_sorted, is_sorted_until (1)
  13. 2011.04.20 Native C++ 개발자를 위한 C++/CLI (3)
  14. 2011.04.19 [STL] 9. <algorithm>에 추가된 새로운 함수들 is_partitioned, partition_point (1)
  15. 2011.04.19 STL을 아직 공부하지 않으신 분들은 이 글들을 참고하세요
  16. 2011.04.12 [STL] 8. <algorithm>에 추가된 새로운 함수들 - partition_copy (2)
  17. 2010.11.17 [Step. 17] 델리게이트에 비관리 함수를 할당하기 그리고 다음 예고 (2)
  18. 2010.07.30 [Step. 07] 비관리 클래스에서 관리 클래스를 멤버로, 관리 클래스에서 비관리 클래스를 멤버로
  19. 2010.07.23 [Step. 06-2] 관리코드의 문자열과 비관리코드의 문자열 변환 (3)
  20. 2010.07.16 [Step. 06-1] 관리코드의 문자열과 비관리코드의 문자열 변환

[ VC11 ] 대격변(?) Visual C++ 11

Visual C++ 10 2012.06.25 09:00 Posted by 흥배

드디어 Visual Studio 2012(이하 VS2012) RC판이 나왔습니다(사실 꽤 되었죠^^;). 

이번 VS Visual C++(이하 VC++)의 버전은 11이 됩니다.

 

한동안 Visual C++은 변화가 거의 없다가 VC++ 9(VS 2008)에서 변화의 조짐을 보이다가 VS 2010에서 새로운 C++ 표준인 C++11(그 당시에는 C++0x라고 부름)과 병렬 프로그래밍, 툴의 기능 강화를 통해서 이전에 비해서 큰 변화를 이루었습니다.

또 이번 VS 2012에서도 VS 2010 버전 이상으로 큰 변화가 생겼습니다. 변화는 대격변이라고 부를 수 있을 정도입니다!.

 

 

이번에는 다음과 같은 변화가 있습니다.

 

1. Windows 8 Metro 앱 개발

아주 큰 변화 중의 하나입니다. 정식 제품이 가을쯤에 나올 Windows 8 Metro Windows Phone 8용 앱을 C++을 사용하여 개발할 수 있습니다. 이것을 위해 WinRT라는 새로운 플랫폼 API C++/CX가 새로 생겼습니다.

 

2. 툴 기능

다양한 C++ 토큰들에 다양한 색을 지정.

찾을 요소를 눈에 잘 뛰게 해준다.

편의 기능이 코딩 시 멤버 선택.

인텔리센스에서 C++/CLI 지원.

코드스니펫을 이용한 고속 코딩.

 

3. C++11 지원

이번에는 코어 언어 기능 보다는 라이브러리 기능이 더 중심이 되었습니다. 그러나 코어 언어에서 VC++ 10에서 큰 사랑을 받은 auto에 버금가는 range-based for loop가 있습니다. 그리고 라이브러리에 Thread가 추가 되었습니다. 이번에는 공부할 것이 많습니다 ^^;

 

4. 컴파일러 개선

CPU 개수에 맞추어 컴파일 속도가 향상.

Auto-Vectorizer 의한 프로그램 성능 향상.

 

5. 병렬 프로그래밍

기존의 병렬 라이브러리 개선.

새로운 디버깅 및 시각화 기능에 의해 쉽고 올바른 병렬 프로그래밍 진단.

GPU 병렬 프로그래밍을 위한 C++ AMP 추가.

 

6. 네이티브 유닛테스트 프레임웍 추가

사제가 아닌 마이크로소프트 순정의 유닛테스트 프레임웍!!!.

 

 

 

이렇게 VC++ 11의 새로운 기능을 정리해 보았습니다. 제가 대충 큰 것만 정리했는데도 공부할 것이 많지 않습니까?^^; 한번에 다 하면 부담되지만 조금씩 하면 충분히 공부할만한 분량입니다. 아직 정식 버전이 나오지 않았으니(가을쯤에 나온다고 합니다) 여유를 가지고 지금부터 조금씩 천천히 공부해 보죠^^

 

 

 

 

 

ps 1: VC++의 각 버전 별 내부 버전 번호와 코드에 정의된 버전

브랜드 버전                  내부 버전          #define _MSC_VER 버전

Visual C++ 2005            VC8                 1400

Visual C++ 2008            VC9                 1500

Visual C++ 2010            VC10                1600

Visual C++ 2012            VC11                1700

 

 

ps 2: 실행 환경

위에는 VC++11의 좋은 점만 이야기 했지만 개인적으로 걱정되는 것이 있습니다. 가장 큰 문제가 실행 환경입니다. VC++11Windows Vista 이상에서만 실행되고 또 VC++11을 이용해서 만든 프로그램도  Windows Vista  이상에서만 실행할 수 있습니다.

Windows 8 Metro 앱 개발을 하거나 저처럼 서버 개발을 하는 개발자에게는 큰 문제가 되지 않을 수도 있지만 클라이언트 개발자에게는 이 부분이 VC++11을 사용하는데 큰 걸림돌이 되리라 생각합니다

 => 그런데 VC++ 팀블로그를 보니 많은 고객들이 XP 지원을 요청해서 가을쯤에 업데이트를 통해서 XP도 지원해 준다고 합니다.^^ 

http://blogs.msdn.com/b/vcblog/archive/2012/06/15/10320645.aspx

이로써 큰 고민을 하나 해결 되었네요^^

 

저작자 표시
신고

[미리 보는 C++11] 8. Placement Insert

C++0x 2012.02.27 09:00 Posted by 흥배

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

 

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 InsertC++11의 새로운 기능인 가변 인수 템플릿을 사용하여 구현되었습니다.

 

 

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

1. explicit 문제.

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


2. "0" 문제.

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

 

저작자 표시
신고

[미리 보는 C++11] 4. constexpr - 2

C++0x 2011.09.23 09:30 Posted by 흥배

constexpr를 클래스에 사용


constexpr을 클래스에서 사용하면 클래스를 정수로 사용할 수도 있으며 메타 템플릿 프로그래밍에서는 이전에는 복잡하게 처리하던 것을 아주 간단하게 처리할 수도 있습니다. C++ 메타 템플릿 프로그래밍에 관심이 많구나 자주 사용하고 있는 분들에게는 constexpr 덕분에 프로그래밍이 한결 편해지리라 생각합니다.

 

아래의 코드는 Integer 이라는 클래스를 constexpr을 사용하여 정수처럼 사용 합니다.

class Integer

{

private :

    int value ;

 

public :

    constexpr Integer() : value() { }

    constexpr Integer( int value ) : value(value) { }

 

    constexpr operator int() { return value ; }

} ;

 

int main()

{

    constexpr Integer size = 5 ; // 컴파일 타임에 정수로

 

    int x[size] ; // Integer::operator int()가 호출된다

 

    Integer object ; // 일반적인 클래스 인스턴스 화. 실행 시에 처리

    int y[object] ; // 당근 에러

}

출처 : http://cpplover.blogspot.com/2010/11/gccniconstexpr.html

 


또 메타 템플릿 프로그래밍에서는 아래와 같이 사용할 수도 있습니다.

#include <iostream>

 

struct pi {

    static constexpr double value = 3.14;

};

 

template <const double& r>

struct circle_area {

    static constexpr double value = r * r * pi::value;

};

 

struct radius {

    static constexpr double value = 2.5;

};

 

int main()

{

    constexpr double result = circle_area<radius::value>::value;

 

    static_assert(result == 19.625, "not equal");

    std::cout << result << std::endl;

}

출처 : http://d.hatena.ne.jp/faith_and_brave/searchdiary?word=constexpr&.submit=%B8%A1%BA%F7&type=detail

 

 

constexpr은 컴파일 할 때 결과가 이미 결정 나는 것은 컴파일 타임 때 처리를 해주어 실행 시에 불필요한 처리를 막아주고, 기존의 메타 템플릿 프로그래밍으로 까다롭게 만들었던 것을 아주 쉽게 구현할 수 있게 해줍니다.

 

C++11에서는 constexpr을 잘 사용하면 기존 보다 더 뛰어난 프로그래밍을 할 수 있으니 깊게 파고들 가치가 있다고 생각합니다.

저작자 표시
신고

[미리 보는 C++11] 3. constexpr - 1

C++0x 2011.09.15 09:00 Posted by 흥배

constexpr는 변수, 함수, 클래스를 컴파일 타임에 정수로 사용할 수 있도록 해줍니다. 즉 상수로 취급할 수 있는 작업은 컴파일 타임에 처리하도록 할 수 있습니다.

 

constexpr를 변수에 사용

constexpr int aa = 11;

이것은

const int aa = 11

와 같은 의미를 가집니다.

 

그러나 아래와 같이는 사용할 수 없습니다.

int input_num = 0;

constexpr int aa = input_num;  // 에러


constexpr
로 지정된 변수는 꼭 컴파일 시에 정수가 되기 때문에 변수 선언 시 대입이 정수 식이어야만 합니다. const와의 차이는 const는 컴파일 시에 정수가 아니어도 괜찮고 변수 선언 시 대입 값이 정수 식인 경우 정수 식이 되고, 그렇지 않은 경우는 단순히 const를 수식하는 것이 됩니다(이에 비해 constexpr는 꼭 정수 식이어야만 합니다).

 

 

 

constexpr를 함수에 사용

C++03에서는 아래의 코드는 에러가 됩니다.

int GetNum() { retun 5; }

int Numbers[ GetNum() ];

GetNum 함수는 상수 5를 반환 하는 것으로 이미 컴파일 시에 반환 값을 알 수 있습니다. 그러나 컴파일러는 GetNum 이라는 함수가 정수처럼 사용할 수 있는지 알 수 없으므로 정수로 취급하지 않습니다.

 

위 코드는 C++11constexpr를 사용하면 우리가 원하는 대로 GetNum 함수를 정수로 사용할 수 있습니다.

 

constexpr int GetNum() { retun 5; }

int Numbers[ GetNum() ];

 

constexpr를 함수에 사용할 때는 꼭 함수 본체는 { return expression; } 형태가 되어야만 합니다.

 

 

constexpr 변수는 비 constexpr 변수에 사용할 수 있으므로 아래와 같은 테크닉도 사용할 수 있다.

constexpr double power( double x, unsigned int y )

{

    return y == 1 ? x : x * power( x, y - 1 ) ;

}

 

int main()

{

    // 정수 식

    constexpr double a = power( 2, 32 ) ;

 

    // 정수 식이 아니다

    double x = 2 ; unsigned int y = 32 ;

    double b = power( x, y ) ;

}

(출처) http://cpplover.blogspot.com/2010/11/gccniconstexpr.html

 

 

그리고

const int base_HP = 200;

int NPC_Lv1_HP = base_HP + 0;

int NPC_Lv2_HP = base_HP + 200;

라는 코드는 정수 계산을 하는데 실행 시에 계산되는데 이것을 constexpr을 사용하여 컴파일 시에 계산되게 할 수 있습니다.

 

constexpr int AssignHP( int nPlusHP )

{

 return base_HP + nPlusHP;

}

 

int NPC_Lv1_HP = AssignHP( 0 );

int NPC_Lv2_HP = AssignHP( 200 );



 

저작자 표시
신고

[미리 보는 C++11] 2. override와 final

C++0x 2011.08.30 00:18 Posted by 흥배

현재의 표준 C++에서는 부모 클래스의 특정 멤버를 오버라이드 할 때 virtual을 앞에 붙입니다.

struct Base

{

  virtual void foo( int i );

};

 

struct Derived : Base

{

  virtual void foo( int i );

}

 위의 예제와 같은 작은 코드를 만질 때는 실수를 하지 않지만 실제 일을 할 때는 크고 많은 클래스를 다루다 보면 실수를 할 수 있습니다. 위 예제의 경우 아래와 같은 실수를 할 수 있습니다.

struct Derived : Base

{

  virtual void foo( float i );

}

위와 같이 실수를 하면 Derived의 foo 멤버함수는 Base foo 멤버함수를 오버라이드 하지 않게 됩니다. 이런 실수는 에러가 아니기 때문에 골치 아픈 삽질을 할 수도 있습니다.

이런 문제를 방지하기 위해서 override가 새로 생겼습니다.

struct Derived : Base

{

  virtual void foo( float i ) override;

}

이렇게 override를 사용하게 되면 컴파일 할 때 Base 클래스에

void foo( float i )가 없는데 오버라이드 한다고 에러를 발생시켜 줍니다.

 

 

때로는 Base 클래스의 특정 멤버함수를 Derived 클래스에서 오버라이드 하지 못하도록 막고 싶은 경우가 있을 것입니다. 이때는 final을 사용합니다.

struct Base

{

  virtual void foo( int i ) final;

};

 

struct Derived : Base

{

  virtual void foo( int i );

}

위의 코드에서는 Base 클래스의 foo 멤버함수를 final로 오버라이드 못하도록 해 놓았기 때문에 컴파일을 하면 에러가 발생합니다.

 

 

 

참고

위키피디아 http://en.wikipedia.org/wiki/C%2B%2B0x

 

저작자 표시
신고
앞으로 조금씩이라도 꾸준히 C++11에 새로 추가되는 기능들을 간단하게 소개하려고 합니다.
새로운 라이브러리의 경우 boost 라이브러리에 있는 것은 boost 라이브러리를 통해서 예제와 같이
좀더 자세하게 설명하고 그렇지 못한 것들은 간단한 설명과 코드로만 설명하려고 합니다.

C++ 프로그래머에게 새로운 C++ 표준은 먼 미래의 것이 아닙니다. 지금부터 조금씩 공부해보죠^^
(개인적으로 예전에 STL의 경우를 보면 앞으로 C++11을 아는 C++ 프로그래머와 모르는 프로그래머로 나누어지지 않을까 생각합니다)



현재의 C++에서는 두 가지 종류의 문자형을 지원하고 있습니다. char wchar_t 입니다.

char szName[] = “jacking”;

wchar_t szName2[] = L”jacking”;

 

그러나 C++0x에서는 유니코드를 강력하게 지원하기 위해 새로운 문자형이 추가 됩니다.

 

 

 

UTF-8

UTF-8을 사용하는 문자형은 따로 없고 기존의 char를 사용합니다.

char szName[] = u8”jacking”;

문자열 리터럴(literal) 앞에 u8을 붙입니다.

 

 

UTF-16

UTF-16을 사용하는 문자형 변수를 선언할 때는 char_16t를 사용합니다.

char16_t szName3[] = u”jacking”;

문자열 리터럴 앞에 u를 붙입니다.

 

 

UTF-32

UTF-32을 사용하는 문자형 변수를 선언할 때는 char_32t를 사용합니다.

char32_t szName4[] = U”jacking”;

문자열 리터럴 앞에 U를 붙입니다.



저작자 표시
신고

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

저작자 표시
신고

앞에까지는 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 eraseforward_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

 

저작자 표시
신고

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;

}

 

< 결과 >


 

저작자 표시
신고

데이터셋을 시퀸스(연속적인)한 값으로 채우고 싶을 때는 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의 세 번째 인자의 값이 시작 값이고, 이후에 값이 하나씩 증가합니다.

 

저작자 표시
신고

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


저작자 표시
신고

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

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

 

is_sortedis_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_sortedis_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;

}

 

< 결과 >


 

 

저작자 표시
신고

Native C++ 개발자를 위한 C++/CLI

C++/CLI 2011.04.20 09:00 Posted by 흥배

제가 http://vsts2010.tistory.com/category/C++/CLI 에 올린 글을 정리한 것으로 보기 편하도록 정리하여 pdf 파일로 만들었습니다.

이후 관련 글을 포스팅 하면 일정 시간이 지난 후 다시 이 글에도 추가하여 배포할 예정입니다.





저작자 표시
신고

이번에 설명할 is_partitioned, partition_point는 그 이름처럼 앞서 소개한 partition_copy와 관계가 있는 알고리즘 입니다.

 

is_partitioned의 원형

template<class InputIterator, class BinaryPredicate>

    bool is_partitioned(

        InputIterator _First,

        InputIterator _Last,

        BinaryPredicate _Comp

    );

 

partition_point의 원형

template<class ForwardIterator, class Predicate>

    ForwardIterator partition_point(

        ForwardIterator _First,

        ForwardIterator _Last,

        Predicate _Comp

    );

 

is_partitioned는 데이터셋의 요소가 전반 부와 후반 부 두 개로 나누어져 있는지 조사할 때 사용하고, partition_point는 두 개로 나누어져 있는 데이터셋에서 후반 부의 첫 번째 요소를 가리키는 반복자를 반환합니다.

 

약간 설명이 애매하죠?^^;

예를 들어 설명하면 온라인 FPS 게임에서 8명이 각각 4명씩 레드 팀과 블루 팀으로 나누어서 게임을 하는 경우 vector로 된 StagePlayers(온라인 게임에서 방에 들어온 유저들을 저장)에 앞 부분에는 레드 팀 플레이어 4명을 차례로 저장하고, 그 이후에 블루 팀 플레이어를 저장하고 있는지 조사하고 싶을 때 is_partitioned 알고리즘을 사용하면 알 수 있습니다(맞다면 true를 반환합니다). 그리고 StagePlayers에서 블루 팀의 첫 번째 플레이어에 접근하고 싶다면 partition_point를 사용합니다.  


나름 쉽게 설명한다고 했는데 이해 가시나요? 만약 이해가 안 간다면 예제 코드를 봐 주세요^^

 

< 예제 >

#include <iostream>

#include <algorithm>

#include <vector>

#include <list>

using namespace std;

 

struct PLAYER

{

           int CharCD;

           bool IsRedTeam;

};

 

 

int main()

{

           vector< PLAYER > StagePlayers1;

           PLAYER player1; player1.CharCD = 1;         player1.IsRedTeam = true;           StagePlayers1.push_back( player1 );

           PLAYER player2; player2.CharCD = 2;         player2.IsRedTeam = true;           StagePlayers1.push_back( player2 );

           PLAYER player3; player3.CharCD = 3;         player3.IsRedTeam = true;           StagePlayers1.push_back( player3 );

           PLAYER player4; player4.CharCD = 4;         player4.IsRedTeam = false;                      StagePlayers1.push_back( player4 );

           PLAYER player5; player5.CharCD = 5;         player5.IsRedTeam = false;                      StagePlayers1.push_back( player5 );

           PLAYER player6; player6.CharCD = 6;         player6.IsRedTeam = false;                      StagePlayers1.push_back( player6 );

           PLAYER player7; player7.CharCD = 7;         player7.IsRedTeam = false;                      StagePlayers1.push_back( player7 );

 

           bool IsPartitioned = is_partitioned( StagePlayers1.begin(), StagePlayers1.end(),

                                                                                     []( PLAYER player ) -> bool { return player.IsRedTeam; } );

           if( IsPartitioned ) {

                     cout << "레드 팀과 블루 팀으로 구분 되어 나누어져 있습니다." << endl;

           } else {

                     cout << "레드 팀과 블루 팀으로 구분 되어 있지 않습니다." << endl;

           }

 

           vector< PLAYER >::iterator IterFirstBlueTeamPlayer = partition_point( StagePlayers1.begin(),StagePlayers1.end(),

                                                     []( PLAYER player ) -> bool { return player.IsRedTeam; } );

           if( IterFirstBlueTeamPlayer != StagePlayers1.end() ) {

                     cout << "첫 번째 블루 팀 플레이어. 캐릭터 코드 : " << (*IterFirstBlueTeamPlayer).CharCD << endl;

           }

 

                    

           vector< PLAYER > StagePlayers2;

           StagePlayers2.push_back( player7 );

           StagePlayers2.push_back( player6 );

           StagePlayers2.push_back( player1 );

           StagePlayers2.push_back( player5 );

           StagePlayers2.push_back( player4 );

           StagePlayers2.push_back( player3 );

           StagePlayers2.push_back( player2 );

          

           IsPartitioned = is_partitioned( StagePlayers2.begin(), StagePlayers2.end(),

                                                                                     []( PLAYER player ) -> bool { return player.IsRedTeam; } );

           if( IsPartitioned ) {

                     cout << "레드 팀과 블루 팀으로 구분 되어 나누어져 있습니다." << endl;

           } else {

                     cout << "레드 팀과 블루 팀으로 구분 되어 있지 않습니다." << endl;

           }

 

           getchar();

           return 0;

}

 

< 결과 >

 

예제 코드를 보니 쉽게 이해 되시죠? 그럼 저는 아는 걸로 생각하고 다음 포스팀에서는 다른 알고리즘을 설명하겠습니다^^

 

 

저작자 표시
신고
제가 현재 VC++ 10에 추가된 C++0x의 새로운 알고리즘들을 소개하고 있습니다.
그런데 만약 STL에 대해서 모르시는 분들은 제가 올린 글들을 이해하기 힘드리라 생각합니다.

제가 예전에 한빛미디어사의 한빛네트워크 사이트에 STL과 관련된 글을 연재한 적이 있습니다.
여기의 글들을 보면 STL을 이해하는데 조금이나마 도움이 되지 않을까 생각합니다.


STL은 어려운 내용은 아니지만 어설프게 사용하면 형편 없는 결과를 얻기도 하니 기본적인 부분은
꼭 잘 배우기를 바랍니다( 최소한 STL의 각 컨테이너의 특징과 어떤 자료구조로 만들어져 있는지는
알고 있어야 합니다 ).
C++ 프로그래머로서 STL을 아는 것은 필수이니 아직 배우지 못한 분들은 꼭 공부하세요!! ^^


저작자 표시
신고
TAG C++, STL, 흥배

partition_copy 알고리즘은 하나의 집단에서 서로 다른 두 개의 집단으로 나눌 때 사용하는 것이라고 아주 간단하게 말할 수 있습니다.

 

partition_copy

template<class InputIterator, class OutputIterator1, class OutputIterator2, class Predicate>

    pair<OutputIterator1, OutputIterator2>

        partition_copy(

            InputIterator _First,

            InputIterator _Last,

            OutputIterator1 _Dest1,

            OutputIterator2 _Dest2,

            Predicate _Pred

        );

 데이터셋의 _First _Last 사이에 있는 각 요소 x를 조건자 _Pred에 인자를 넘겼을 때 true를 반환하면 x _Dest1, false를 반환하면 _Dest2에 복사하고 지정된 구간의 모든 요소를 다 처리하면 OutputIterator 값을 pair로 반환한다

 

그럼 좀 더 쉽게 이 알고리즘을 어떤 경우에 사용하는지 알 수 있도록 간단한 예제를 하나 보여드리겠습니다.

 ) 게임 아이템들을 팔 수 있는 것과 팔 수 없는 것으로 나누어라

#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;

struct ITEM
{
    int nItemCode;
    bool bEnableSell;
};

int main()
{
    vector< ITEM > AllItems;
    ITEM item1; item1.nItemCode = 1;    item1.bEnableSell = false;        AllItems.push_back( item1 );
    ITEM item2; item2.nItemCode = 2;    item2.bEnableSell = true;        AllItems.push_back( item2 );
    ITEM item3; item3.nItemCode = 3;    item3.bEnableSell = true;        AllItems.push_back( item3 );
    ITEM item4; item4.nItemCode = 4;    item4.bEnableSell = false;        AllItems.push_back( item4 );
    ITEM item5; item5.nItemCode = 5;    item5.bEnableSell = true;        AllItems.push_back( item5 );
    ITEM item6; item6.nItemCode = 6;    item6.bEnableSell = false;        AllItems.push_back( item6 );
    ITEM item7; item7.nItemCode = 7;    item7.bEnableSell = true;        AllItems.push_back( item7 );

    ITEM UnItem; UnItem.nItemCode = 0;
    list< ITEM > SellItems( 7, UnItem );            
    list< ITEM > UnSellItems( 7, UnItem );
    
    pair<list< ITEM >::iterator, list< ITEM >::iterator > SeperateItems;
    SeperateItems = partition_copy( AllItems.begin(), AllItems.end(),
                                                 SellItems.begin(),
                                                 UnSellItems.begin(),
                                                   []( ITEM& item ) { return item.bEnableSell; } );

    cout << "팔 수 있는 아이템" << endl;
    for each( ITEM item in SellItems )
    {
        if( item.nItemCode <= 0 ) {
            continue;
        }
        cout << "아이템 코드 : " << item.nItemCode << endl;
    }

    cout << endl << endl;

    cout << "팔 수 없는 아이템" << endl;
    for( auto Iter = UnSellItems.begin(); Iter != UnSellItems.end(); ++Iter )
    {
        if( Iter->nItemCode <= 0 ) {
            continue;
        }
        cout << "아이템 코드 : " << Iter->nItemCode << endl;
    }
    
    getchar();
    return 0;
}

< 결과 >


partition_copy를 사용할 때 한 가지 주의할 점은 결과를 다른 컨테이너에 복사를 하므로 해당 컨테이너에 공간이

확보되어 있어 있어야 합니다. 그래서 위의 예제에도

ITEM UnItem; UnItem.nItemCode = 0;
list< ITEM > SellItems( 7, UnItem );            
list< ITEM > UnSellItems( 7, UnItem );

로 더미 값을 넣어서 복사할 공간을 확보하고 있습니다.

 

참조 : http://msdn.microsoft.com/ko-kr/library/ee384416.aspx

 

저작자 표시
신고

MSDN을 보다 보니 C++/CLI의 델리게이트에 네이티브용 함수를 할당할 수 있는 방법이 있어서 소개합니다. 아래의 코드는 MSDN에 있는 것입니다.

 

#pragma unmanaged

extern "C" void printf(const char*, ...);

class A {

public:

   static void func(char* s) {

      printf(s);

   }

};

 

#pragma managed

public delegate void func(char*);

 

ref class B {

   A* ap;

 

public:

   B(A* ap):ap(ap) {}

   void func(char* s) {

      ap->func(s);

   }

};

 

int main() {

   A* a = new A;

   B^ b = gcnew B(a);

   func^ f = gcnew func(b, &B::func);

   f("hello");

   delete a;

}

< http://msdn.microsoft.com/ja-jp/library/9cy3ccxx%28v=VS.80%29.aspx >

 

위 코드 중 #pragma unmanaged 지시어 이하는 컴파일러에서 비관리코드로 취급합니다. 그리고 #pragma managed 이하는 관리코드로 취급합니다. 내용이 간단하고 어려운 부분이 없기 때문에 따로 자세한 설명은 생략하겠습니다.

 


C++/CLI는 단순하게 닷넷 플랫폼에서 사용할 수 있는 C++ 언어라기 보다는 C++ 언어의 부족한 부분을 진화 시킨 언어라고도 생각할 수 있는 부분이 꽤 있습니다. 그러나 C++/CLI는 C++과 C#의 중간의 애매한 위치에 있어서 양쪽 프로그래머 모두에게 별로 호응을 받지 못하는 것 같습니다. 그래서 C++/CLI 관련 글을 제가 처음에 생각했던 것보다는 조금 일찍 끝낼려고 합니다.

C++/CLI를 사용하는 대부분의 프로그래머들은 아마 기존의 비관리 코드를 관리코드에서 사용하고 싶을 때라고 생각합니다. C++/CLI의 기능 소개는 이번으로 일단 끝내고 앞으로는 비관리코드와의 연계에 대해서 실제 사례 보여주면서 설명하려고 합니다.


사례는 오픈 소스 네트워크 라이브러리인 HalfNetworkC++/CLI를 사용하여 관리코드에서 사용할 수 있도록 wrapping한 후 이것을 관리코드에서 사용할 예정입니다.

HalfNetwork는 온라인 게임 서버 프로그래머인 임영기님이 만든 것으로 ACE 라는 오픈 소스 네트워크 라이브러리를 사용하기 편하게 만든 라이브러리입니다.

 

소스 위치 http://code.google.com/p/halfnetwork/

문서 http://code.google.com/p/halfnetwork/w/list http://jacking.tistory.com/category/HalfNetwork

임영기님 블로그 http://javawork.egloos.com/

 

요즘 공부할 것은 너무 많은데 따라갈 시간은 부족해서 다음 글은 언제쯤 올리지 정확하게 알 수 없지만 최대한 빨리 다음 글들을 올려서 C++/CLI을 2010년 안에는 끝내고 내년에는 새로운 주제로 시작하겠습니다^^

 

저작자 표시
신고

1. 비관리 클래스에서 관리 클래스를 멤버로

 

비관리 클래스에서 관리 클래스를 멤버로 가지고 싶을 때는 ‘gcroot’라는 템플릿을 사용합니다.

 

#include "stdafx.h"

#include <iostream>

#include <vcclr.h>

 

using namespace System;

 

class TEST

{

public:

   TEST() {}

   ~TEST() {}

 

   gcroot< String^ > m_str;

};

 

int main(array<System::String ^> ^args)

{

    TEST test;

    test.m_str = gcnew String("Hello VSTS 2010");

 

    Console::WriteLine( test.m_str);

   

    getchar();

    return 0;

}

 



‘gcroot’를 사용하기 위해서는

#include <vcclr.h>

를 포함해야 합니다.

 

비관리 클래스에서 관리 클래스인 String을 다음과 같이 멤버로 선언합니다.

gcroot< String^ > m_str;


그리고 사용하기 위해서는 할당을 합니다.

test.m_str = gcnew String("Hello VSTS 2010");

 

 



2. 관리 클래스에서 비관리 클래스를 멤버로

 

관리 클래스에서 비관리 클래스를 멤버로 가질 때는 비관리 클래스를 포인터로 선언하여 비관리 힙에 동적할당을 합니다.

 

#include "stdafx.h"

#include <iostream>

#include <vcclr.h>

 

using namespace System;

 

class TEST

{

public:

       TEST() {}

       ~TEST() {}

};

 

ref class refTEST

{

public:

       refTEST() {}

       ~refTEST() {}

 

       TEST* test;

};

 

int main()

{

       refTEST^ refTest = gcnew refTEST();

       refTest->test = new TEST;

 

       return 0;

}

 

 

 

참고

http://msdn.microsoft.com/ko-kr/library/481fa11f%28v=VS.80%29.aspx

http://blog.naver.com/scor7910/40048083284

 


 

저작자 표시
신고

3) String^ C/C++ 문자열로 변환

 

1)번에서는 C/C++의 문자열을 String^로 변환하는 방법에 대해서 설명했습니다.

이번에는 String^ char* wchr_t*로 변환하는 방법에 대해서 설명합니다.

 

아래의 예제 코드를 봐 주세요

 

#include <string>

#include <msclr\marshal_cppstd.h>

 

using namespace System;

using namespace msclr::interop;

 

int main()

{

           System::String^ s0 = L"비주얼스튜디오2010 팀블로그";

          

           // 방법 1

           std::string tmp = marshal_as<std::string>(s0);

           const char* s1 = tmp.c_str();

           std::cout << "String^ -> string : " << s1 << std::endl;

 

           // 방법 2

           const char* s2;

           const wchar_t* s3;

           {

                     marshal_context ctx;

                     s2 = ctx.marshal_as<const char*>(s0);

                     s3 = ctx.marshal_as<const wchar_t*>(s0);

            

                     std::cout << "String^ -> char* : " << s2 << std::endl;

                    

                     setlocale(LC_ALL, "");

                     std::wcout << "String^ -> wchar_t : " << s3 << std::endl;

           }

 

           getchar();

           return 0;

}

 

String^ char* wchr_t*로 변환하는 방법은 두 가지가 있습니다.

 


첫 번째 std::string 사용


가장 간단한 방법입니다만 불필요한 std::string을 사용해야 단점이 있습니다.

std::string tmp = marshal_as<std::string>(s0);

const char* s1 = tmp.c_str();

std::cout << "String^ -> string : " << s1 << std::endl;

 

 

두 번째 marshal_context 사용


첫 번째 방법에서 std::string을 사용한 이유는 다름이 아니고 메모리 확보 때문입니다.

마샬링을 통해서 char* wchar_t*에 메모리 주소를 저장합니다. 문자열 그 자체를 복사하는 것이 아닙니다. 그래서 변환한 문자열을 저장할 메모리 주소를 확보하고 사용 후에는 해제를 해야 합니다. 메모리 확보와 해제를 위해서 marshal_context를 사용합니다.

marshal_context는 변환에 필요한 메모리를 확보하고, 스코프를 벗어날 때 메모리를 해제합니다.

const char* s2;

const wchar_t* s3;

{

           marshal_context ctx;

           s2 = ctx.marshal_as<const char*>(s0);

           s3 = ctx.marshal_as<const wchar_t*>(s0);

}

 

String^ C/C++ 문자열로 변환할 때는 std::string + marshal_as marshal_context 둘 중 하나를 선택하여 사용합니다.

 




참고

http://msdn.microsoft.com/en-us/library/bb384865.aspx

http://msdn.microsoft.com/ko-kr/library/bb531313%28VS.90%29.aspx

http://codezine.jp/article/detail/4774

저작자 표시
신고

관리코드와 비관리코드를 혼합해서 사용할 때 서로간에 문자열을 주고 받아야 하는 경우가 종종 있을 것입니다. 관리코드와 비관리코드간에 문자열을 서로 어떻게 변환하여 주고 받는지 알아보겠습니다.

 

 

1) C/C++ 문자열을 String^으로 변환

 

먼저 아래의 변환 예제 코드를 봐 주세요

 

#include <msclr\marshal.h>

 

using namespace System;

using namespace msclr::interop;

 

int main()

{

           const char* message = "Forever Visual C++";

           String^ result1 = marshal_as<String^>( message );

           Console::WriteLine("char -> System::String : {0}", result1);

 

           const wchar_t* Wmessage = L"Visual C++이여 영원하라";

           String^ result2 = marshal_as<String^>( Wmessage );

           Console::WriteLine("wchar -> System::String : {0}", result2);

 

           getchar();

           return 0;

}

 


관리코드와 비관리코드 간의 문자열 변환에는 msrshal_as를 사용하여 마샬링합니다.

C/C++ 문자열을 마샬링하기 위해서는

#include <msclr\marshal.h>

파일을 포함하고,


using namespace msclr::interop;

네임스패이스를 선언합니다.

 

사용 방법은 아주 간단합니다.

marshal_as< 변환할 문자 타입 >( 원본 문자열 );

 


ANSI 문자열을 관리코드의 문자열로 변환할 때는 아래와 같이 합니다.

const char* message = "Forever Visual C++";

String^ result1 = marshal_as<String^>( message );

 

유니코드를 관리코드의 문자열로 변환할 때는 아래와 같이 합니다.

const wchar_t* Wmessage = L"Visual C++이여 영원하라";

String^ result2 = marshal_as<String^>( Wmessage );

 

 



2) STL string String^간의 변환

 

이것도 marshal_as를 사용합니다.

아래의 예제 코드를 봐 주세요

 

#include <iostream>

#include <string>

#include <msclr\marshal_cppstd.h>

 

using namespace System;

using namespace msclr::interop;

 

int main()

{

           std::string s0 = "비주얼스튜디오2010 팀블로그";

           std::cout << "string : " << s0 << std::endl;

 

           System::String^ s1 = marshal_as< System::String^ >(s0);

           Console::WriteLine("std::sting->System::String : {0}", s1);

 

           std::wstring s2 = marshal_as< std::wstring >(s1);

           setlocale(LC_ALL, "");

           std::wcout << "System::String->std::wstring : " << s2 << std::endl;

          

           getchar();

           return 0;

}

 

STL의 문자열과 변환하기 위해서는 다음의 헤더 파일을 포함해야 합니다.

#include <msclr\marshal_cppstd.h>

 

마샬링하는 방법은 앞에 설명한 C/C++ 문자열 변환과 같습니다.

System::String^ s1 = marshal_as< System::String^ >(s0);

 

주제와 좀 관계 없는 것으로 콘솔창에 유니코드 문자열을 출력하는 방법은 아래와 같습니다.

setlocale(LC_ALL, "");

std::wcout << "System::String->std::wstring : " << s2 << std::endl;

 setlocale로 국가를 설정하고(직접 나라를 지정할 수도 있고, 아니면 위처럼 시스템 설정에 따라가도록 할 수도 있습니다), ‘cout’ 대신 ‘wcout’를 사용합니다.

 

 



관리코드 문자열과 비관리코드 문자열간의 변환에 따른 성능


C++로 만드는 프로그램은 보통 고성능을 원하는 프로그램이므로 보통 C++ 프로그래머는 성능에 민감합니다. 마샬링은 공짜가 아닙니다만 많은 양을 아주 빈번하게 마샬링 하는 것이 아니면 성능에 너무 신경 쓰지 않아도 됩니다. 다만 기본적으로 관리코드의 문자열은 유니코드입니다. 그래서 비관리코드의 문자열이 ANSI 코드라면 유니코드를 사용했을 때 보다 더 많은 시간이 걸립니다(정확한 수치는 잘 모르지만 ANSI가 유니코드보다 3배정도 더 걸린다고도 합니다). 그래서 관리코드와 비관리코드를 같이 사용할 때는 가능한 유니코드를 사용하는 것이 훨씬 좋습니다.

 

 

아직 설명할 것이 많이 남아 있습니다. 다음을 기다려주세요^^

저작자 표시
신고