아래 코드에서 TEST1은 몇 번 생성될까요?


TEST1 GetTest1_1()

{

           TEST1 test1;

           test1.nValue = 11;

 

           return test1;

}

 

int main()

{

           ....

           auto test1_1 = GetTest1_1();

           ....

}

 

위의 코드를 실행하면 main에서 TEST1 객체 생성(1), GetTest1_1() 함수에서 TEST1 객체 생성(2)에 의해 TEST1은 총 2번 만들어집니다.

 

그러나 실제로는 C++ 최적화(즉 릴리즈모드로 컴파일 하면)에 의해 TEST1 객체는 한번만 생성합니다. 위의 최적화를 NRVO라고 합니다(RVO도 있습니다).

 

그런데 NRVO는 한계가 있습니다. 아래와 같은 경우에서는 NRVO 최적화를 사용할 수 없습니다.

 

TEST1 GetTest1_2( int nTemp )

{

           TEST1 test1;

           test1.nValue = 11;

 

           if( nTemp > 100 )

           {

                     test1.nValue = 111;

                     return test1;

           }

 

           return test1;

}

 

코드를 보면 알겠지만 TEST1 객체를 조건문에 의해서 다르게 반환하는 경우 컴파일러는 NRVO 최적화를 하지 않습니다.

 

이때는 C++11 move 생성자를 사용하여 최적화를 할 수 있습니다.

 

C++11에서는 GetTest1_2와 같은 상황일 때 TEST1move 생성자를 정의해 놓으면 컴파일러가 move 생성자를 사용합니다.

당연하겠지만 move 생성자를 정의하고 있어도 NRVO를 사용할 수 있으면 NRVO 최적화를 최우선적으로 사용합니다.

 

 

< 예제 코드 >

#include <iostream>

 

struct TEST1

{

           int nValue;

 

           TEST1()

           {

                     std::cout << "TEST1 생성자" << std::endl;

           }

          

           ~TEST1()

           {

                     std::cout << "TEST1 소멸자" << std::endl;

           }

 

           TEST1(const TEST1& obj)

           {

                     nValue = obj.nValue;

 

                     std::cout << "TEST1 복사 생성자" << std::endl;

           }

};

 

struct TEST2

{

           int nValue;

 

           TEST2()

           {

                     std::cout << "TEST2 생성자" << std::endl;

           }

          

           ~TEST2()

           {

                     std::cout << "TEST2 소멸자" << std::endl;

           }

 

           TEST2(const TEST2& obj)

           {

                     nValue = obj.nValue;

 

                     std::cout << "TEST2 복사 생성자" << std::endl;

           }

          

           TEST2(TEST2&& obj)

           {

                     nValue = obj.nValue;

 

                     std::cout << "TEST2 move 생성자" << std::endl;

           }

};

 

 

TEST1 GetTest1_1()

{

           TEST1 test1;

           test1.nValue = 11;

 

           return test1;

}

 

TEST1 GetTest1_2( int nTemp )

{

           TEST1 test1;

           test1.nValue = 11;

 

           if( nTemp > 100 )

           {

                     test1.nValue = 111;

                     return test1;

           }

 

           return test1;

}

 

TEST2 GetTest2_1()

{

           TEST2 test2;

           test2.nValue = 11;

 

           return test2;

}

 

TEST2 GetTest2_2( int nTemp )

{

           TEST2 test2;

           test2.nValue = 11;

 

           if( nTemp > 100 )

           {

                     test2.nValue = 111;

                     return test2;

           }

 

           return test2;

}

 

int main()

{

           std::cout << "TEST1 - NRVO 사용" << std::endl;

           {

                     auto test1_1 = GetTest1_1();

           }

 

           std::cout << std::endl;

          

           std::cout << "TEST1 - NRVO 사용 불가" << std::endl;

           {

                     auto test1_2 = GetTest1_2(101);

           }

 

           std::cout << std::endl;

           std::cout << std::endl;

          

           std::cout << "TEST2 - NRVO 사용" << std::endl;

           {

                     auto test2_1 = GetTest2_1();

           }

 

           std::cout << std::endl;

          

           std::cout << "TEST2 - move 생성자 사용" << std::endl;

           {

                     auto test2_2 = GetTest2_2(101);

           }

 

          

           return 0;

}

 

< 결과 >


by 흥배 2012.10.24 09:30

range base for는 다 좋은데 조금 아쉬운 부분이 있습니다.

그것은 앞에서 뒤로 순차적으로만 접근이 된다는 것입니다.

때로는 뒤에서부터 시작해야 할 때가 있습니다.

 

이때는 일반적인 방법으로는 안되고 boost 라이브러리의 도움을 받으면 할 수 있습니다.

boost 라이브러리의 boost::adaptors::reverse 를 사용합니다.

 

< 예제. 4 >

#include <iostream>

#include <boost/range/adaptors.hpp>

 

int main()

{

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

 

           for (auto i : boost::adaptors::reverse(NumberList))

           {

                     std::cout << i << "  ";

           }

 

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

 

 

 

           std::vector<int> vecNumberList;

           vecNumberList.push_back( 1 );

           vecNumberList.push_back( 2 );

           vecNumberList.push_back( 3 );

 

           for (auto i : boost::adaptors::reverse(vecNumberList))

           {

                     std::cout << i << "  ";

           }

 

           std::cout << std::endl;

 

           return 0;

}

 

< 실행 결과 >


by 흥배 2012.10.15 09:00

range base for에서 데이터셋의 요소를 변경할 수 있을까요?

정답은 있을 수도 있고, 없을 수도 있습니다.

 

앞 선 예제 코드에서는

for( auto i : NumberList )

이런 식으로 사용했는데 이런 경우 i의 값을 for 문 안에서 변경 할 수 있지만 for 문을 나오면 NumberList의 요소에는 적용되지 않습니다.

 

만약 요소의 값을 변경하고 싶다면 참조를 사용하면 됩니다.

for( auto &i : NumberList )

이런 식으로 하면 for 문을 나와도 NumberList의 요소는 변경이 적용되어 있습니다.

 

그런데 만약 for 문에서 요소 값을 변경하지 못하도록 하려면 const를 사용합니다.

for( auto const i : NumberList )

 

for 문에서 데이터셋 요소를 접근할 때는 임시 변수를 만들기 때문에 이 비용을 줄이고 싶다면 참조를 사용하면 좋습니다.

또 만약 요소의 값을 변경하지 못하도록 하고 싶다면 const 참조를 사용합니다.

for( auto const &i : NumberList )

 


< 예제. 3 >

#include <iostream>

#include <vector>

 

int main()

{

           std::vector<int> NumberList;

           NumberList.push_back( 1 );

           NumberList.push_back( 2 );

           NumberList.push_back( 3 );

          

           for( auto i : NumberList )

           {

                     std::cout << i << " * 10 : ";

 

                     i *= 10;

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

           }

 

           for( auto i : NumberList )

           {

                     std::cout << i << "  ";

           }

          

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

 

 

           for( auto &i : NumberList )

           {

                     std::cout << i << " * 10 : ";

 

                     i *= 10;

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

           }

 

           for( auto i : NumberList )

           {

                     std::cout << i << "  ";

           }

 

           std::cout << std::endl;

 

           return 0;

}

 

< 실행 결과 >




by 흥배 2012.09.26 01:07

너무 당연한 것이지만 range base for에는 배열 뿐만이 아닌 STL의 컨테이너들도 사용할 수 있습니다.

아래 예제를 통해서 STL 컨테이너를 range base for문에서 어떻게 사용하는지 보겠습니다.

 

< 예제. 2 >

#include <iostream>

#include <vector>

#include <unordered_map>

#include <string>

 

int main()

{

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

 

           std::vector<int> NumberList;

           NumberList.push_back( 1 );

           NumberList.push_back( 2 );

           NumberList.push_back( 3 );

          

           for( auto i : NumberList )

           {

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

           }

           std::cout << std::endl;

 

 

 

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

 

           std::unordered_map<int, std::string> NumString;

           NumString.insert( std::make_pair<int, std::string>(1, "1") );

           NumString.insert( std::make_pair<int, std::string>(2, "2") );

           NumString.insert( std::make_pair<int, std::string>(3, "3") );

 

           for( auto i : NumString )

           {

                     std::cout << "key : " << i.first << ", value : " << i.second << std::endl;

           }

 

           std::cout << std::endl;

 

           return 0;

}

 

< 실행 결과 >


 

 

range base for문은 기본적으로 STL의 이터레이터를 지원하는 컨테이너라면 문제 없이 사용할 수 있습니다. 그러므로 프로그래머가 자신만의 컨테이너를 만든다면 STL에서 정의한 이터레이터의 기능을 구현하면 range base for 문을 사용할 수 있습니다.

 

이전에는 STL 컨테이너의 모든 요소를 반복문에서 사용할 때  for_each를 사용했는데 사용하기 위해서 준비해야 할 것이 많았는데 VC10에서 lambda 덕분에 쉬워졌습니다. 그러나 range base for 문과 비교해보면 for_each+lambda 보다는 range base for 문이 더 사용하기 편한 것을 알 수 있습니다.

 

이제 VC11부터 for 반복문은 꼭 range base for를 사용하기 바랍니다^^

by 흥배 2012.09.21 13:01

데이터셋을 시퀸스(연속적인)한 값으로 채우고 싶을 때는 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

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

unique_ptr shard_ptr를 사용하려면 먼저 아래처럼 헤더 파일을 추가해야 합니다.

#include <memory>

 

 

struct TEST

{

        TEST() {}

           ~TEST() {}

};

 

 

1. unique_ptr 동적 배열 사용

std::unique_ptr<TEST[]> pTest( new TEST[2] );

템플릿 부분에 동적 배열임을 알려줘야 합니다.

 

 

2. shard_ptr 동적 배열 사용

std::shared_ptr<TEST> pTest( new TEST[2], std::default_delete<TEST[]>() );

unique_ptr과 조금 다릅니다. 템플릿 부분에는 일반적인 타입을 선언해주면 됩니다. 다만 deleter 부분에 동적 배열임을 선언해줘야 합니다.

 

 

3. unique_ptr 사용 중 할당된 객체의 메모리 해제

std::unique_ptr<TEST> pTest( new TEST );

                    

pTest.reset(nullptr);

 

unique_ptr이 소멸되기 전에 할당된 객체의 메모리를 해제 할 때는 reset을 사용하면 간편합니다.

원래 reset은 다른 객체로 바꿀 때 사용하는 것인데 이런 용도로 사용해도 좋습니다

 

 

 

< 테스트 코드 >

#include <memory>

#include <iostream>

 

 

struct TEST

{

           TEST()

           {

                     std::cout << "TEST 생성자" << std::endl;

           }

 

           ~TEST()

           {

                     std::cout << "TEST 소멸자" << std::endl;

           }

};

 

 

 

int main()

{

           std::cout << "unique_ptr - 동적 배열 사용" << std::endl;

           {

               std::unique_ptr<TEST[]> pTest( new TEST[2] );

           }

           std::cout << std::endl;

 

 

           std::cout << "shared_ptr - 동적 배열 사용" << std::endl;

           {

               std::shared_ptr<TEST> pTest( new TEST[2], std::default_delete<TEST[]>() );

           }

           std::cout << std::endl;

 

 

           std::cout << "unique_ptr - reset 사용" << std::endl;

           {

               std::unique_ptr<TEST> pTest( new TEST );

                    

               std::cout << "unique_ptr - reset 사용 전" << std::endl;

               pTest.reset(nullptr);

               std::cout << "unique_ptr - reset 사용 후" << std::endl;

           }

 

           return 0;

}




 

 

by 흥배 2012.08.20 09:00

예전에  http://jacking.tistory.com/154 이 글을 통해서 간단하게 VC++의 연관 컨테이너의 성능을 테스트해 본적이 있습니다.

그 때는 VC++ 9 환경에서 테스트를 했는데 이번에는 VC++ 11(RC)에서 테스트 해 보았습니다.

그때 사용했던 코드를 거의 그대로 사용했습니다(그래서 손 볼 것이 좀 있습니다^^;)


성능은 역시나(?) CAtlmap이 제일 빠릅니다. 또 unordered_map이 이전에 비해서 많이 빨라졌네요

일전에 VC++ 팀 블로그에서 성능이 개선되었다고 하던데 맞네요


코드를 올리니 혹시 관심 있는 분들은 좀 더 다양하게 테스트 해보시고 공유 부탁합니다^^





ContainerPerformance.zip


by 흥배 2012.07.05 09:00
| 1 2 3 4 5 6 |