C++11에서 STL bind Boost::bind를 같이 사용할 때 아래와 같이 사용하면 이름 충돌이 발생할 수 있습니다.


#include <functional>

using namespace std::placeholders;

#include <boost/bind.hpp>

 

int f(int, int);

auto g = std::bind(f, _1, 42);  // _1 때문에 에러 발생

 

해결 방법은 이름 공간을 정확하게 지정하면 됩니다.

auto g = std::bind(f, std::placeholders::_1, 42);

 

namespace ph = std::placeholders;

auto g = std::bind(f, ph::_1, 42);

 


 

출처 : http://d.hatena.ne.jp/yohhoy/20121129/p1

저작자 표시
신고
by 흥배 2013.03.29 08:00

C++11의 새로운 기능 중 'SCARY iterator' 라는 것이 있습니다. 단순히 한국말로 바꾸면 '무서운 반복자' 라고 할 수 있는데 사실 무섭지는 않습니다.^^;

 

SCARY iterator에 대해서 아주 간단하게 말하면 컨테이너를 선언할 때 템플릿에 들어가는 데이터 타입만 같다면 비교 함수나 메모리 할당자가 서로 달라도 같은 반복자를 사용할 수 있게 해줍니다(만약 메모리 할당자의 차이에 의해서 이상한 결과가 나올 수도 있어서 무서운 이라는 단어를 사용하지 않았나 생각합니다);

 

SCARY iterator가 구현 되기 전에는 아래와 같이 데이터 타입은 같으나 비교 함수가 서로 다른


std::set< int, std::less<int> > map1;

std::set< int, std::greater<int> > map2;


에서 map1 map2의 반복자는 서로 같지 않습니다. 분명히 int라는 같은 타입을 사용해서 같은 반복자를 사용해도 문제 없

을 거라고 생각되지만 비교 함수가 서로 틀려서 반복자는 서로 다른 타입으로 취급합니다. 그래서 아래의 코드는 컴파일 에러가 발생합니다.

 

std::set<int, std::less<int>>::iterator Iter = b.begin();

 

그러나 C++11SCARY iterator가 구현된 VC11에서는 위의 코드는 전혀 에러가 발생하지 않습니다.

 

VC11처럼 SCARY iterator가 구현된 컴파일러에서는 컨테이너의 데이터 타입만 같다면 같은 반복자를 사용할 수 있게 되었습니다.

 

 


 

참고 : http://blogs.wankuma.com/episteme/archive/2013/01/11/311581.aspx

 

저작자 표시
신고
by 흥배 2013.03.21 08:00

VS 2005를 사용하여 만든 프로젝트를 VS2012로 마이그레이션 하는 도중 템플릿 사용 부분에서 에러가 발생했습니다.

 

제가 겪은 에러가 이미 다른 사람들도 경험을 했고 MSConnect 사이트에 해결 책이 있어서 공유합니다.

 

struct default_policy

{

    template<class T>

    struct apply

    {

        typedef T type;

    };

};

 

template<class Policy=default_policy>

struct Def

{

    typedef Policy policy;

    typedef Def<policy> thisClass;

 

    typedef typename policy::apply<thisClass>::type type; // syntax error '<'

};

 

void main()

{

}

위 코드에서 typedef typename policy::apply<thisClass>::type type; 부분에서 에러가 발생합니다.

 

이것은 VC11의 문제가 아니고 위 코드가 표준을 지키지 않아서 발생한 문제입니다.

 

해결책은 아래와 같습니다(간단합니다)

struct default_policy

{

    template<class T>

    struct apply

    {

        typedef T type;

    };

};

template<class Policy=default_policy>

struct Def

{

    typedef Policy policy;

    typedef Def<policy> thisClass;

    typedef typename policy::template apply<thisClass>::type type;

};

 

 

typedef typename policy::apply<thisClass>::type type;

이것을 아래와 같이 바꾸면 됩니다.

typedef typename policy::template apply<thisClass>::type type;

 

 

출처 : http://connect.microsoft.com/VisualStudio/feedback/details/745629/typename-template-bug-in-c-compiler-in-visual-studio-2012-rc

 

 

저작자 표시
신고
by 흥배 2012.11.27 08:00

앞선 글의 <예제.1>을 보면 제일 아래에

 

#include <thread>

#include <iostream>

 

int main()

{

std::thread Thread1( [] ()

......

 

getchar();

return 0;

}

 

마지막 줄에서 두 번째에 getchar();를 사용했습니다. 만약 이것을 제거하고 예제 코드를 실행하면 다음과 같은 에러가 발생합니다.



이 에러가 발생하는 이유는 아직 스레드는 실행 중인데 프로그램이 종료 되었기 때문입니다. getchar();를 사용하여 유저의 입력을 받을 때까지 대기하도록 하여 문제를 해결할 수 있지만 이것은 임시 방편입니다. 올바른 방법은 thread 클래스의 join 함수를 사용하여 스레드의 실행이 끝날 때까지 대기하도록 합니다.

<예제.1> join을 사용하도록 수정하면 아래와 같습니다.

 

< 예제. 2 >

#include <thread>

#include <iostream>

 

int main()

{

std::thread Thread1( [] ()

           {

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

              {

                     std::cout << "Thread Num : " << i << std::endl;

              }

           } );

 

 

           std::thread Thread2;

           Threads = std::thread( [] ()

           {

              for( int i = 10; i < 15; ++i )

              {

                 std::cout << "Thread Num : " << i << std::endl;

              }

           } );

 

           std::thread Thread3 = std::thread( [] ( int nParam )

                     {

                       for( int i = 20; i < 25; ++i )

                       {

                         std::cout << "Thread Parameter : " << nParam << std::endl;

                       }

                      }, 4 );

 

          

 

           Thread1.join();

Thread2.join();

Thread3.join();

          

return 0;

}

 

<예제.2>는 제일 아래에서 각 thread 객체의 join을 호출하고 있어서 Thread1, Thread2, Thread3는 생성과 동시에 실행이 되는데 만약 Thread1의 실행이 끝난 후 Thread2가 실행되고 이것이 끝나면 Thread3를 실행하려면 thread 객체를 생성 후 join을 호출하면 됩니다.

 

< 예제. 3 >

#include <thread>

#include <iostream>

 

int main()

{

std::thread Thread1( [] ()

           {

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

              {

                     std::cout << "Thread Num : " << i << std::endl;

              }

           } );

           Thread1.join();

 

 

           std::thread Thread2;

           Threads = std::thread( [] ()

           {

              for( int i = 10; i < 15; ++i )

              {

                 std::cout << "Thread Num : " << i << std::endl;

              }

           } );

           Thread2.join();

 

 

           std::thread Thread3 = std::thread( [] ( int nParam )

                     {

                       for( int i = 20; i < 25; ++i )

                       {

                         std::cout << "Thread Parameter : " << nParam << std::endl;

                       }

                      }, 4 );

Thread3.join();

          

return 0;

}

 

< 결과 >




저작자 표시
신고
by 흥배 2012.11.19 08:30

멀티 코어 시대인 만큼 요즘은 프로그램들을 평가할 때 멀티코어를 얼마나 잘 활용하나를 중요하게 따집니다. 그래서 프로그래밍 언어나 라이브러리에서 병렬 프로그래밍 지원을 하는 경우가 많습니다. C++11에서도 큰 특징 중의 하나가 thread 라이브러리 지원입니다.

 

VC의 경우는 현재 사용 중인 10에서는 MS 독자의 Concurrency Runtime을 지원하였고, 이번 버전에서는 C++ 표준의 thread 라이브러리를 제공합니다(VC 전용으로 GPGPU 프로그래밍을 위해 AMP 라이브러리도 제공합니다).

 

C++11 thread 라이브러리를 사용하면 기존에 복잡하고, 플랫폼 마다 다르게 기술해야 하는 스레드 프로그래밍을 쉽고, 플랫폼 독립적으로 구현할 수 있습니다.

 

앞으로 몇 번에 걸쳐서 C++11 thread를 다룹니다. 내용이 어렵지 않으니 천천히 따라오시면 됩니다. thread 라는 것이 무엇인지는 책이나 인터넷을 통해서 미리 공부하시기 바랍니다. 따로 thread에 대한 이론 설명을 하지 않겠습니다. ^^;

 

 

 

thread 생성하기

 

thread 라이브러리를 사용하기 위해서는 아래의 헤더 파일을 포함해야 합니다.

#include <thread>

 

thread 클래스의 생성자는 아래와 같습니다.

thread() _NOEXCEPT;

 

template<class Fn, class... Args>

   explicit thread(Fn&& F, Args&&... A);

 

thread(thread&& Other) _NOEXCEPT;

 

 

인자 중 Fn은 생성된 스레가 호출할 함수(애플리케이션에서 정의한), A Fn에 넘겨 줄 인수 리스트, Other는 기존의 스레드 오브젝트 입니다.

 

첫 번째 생성자는 thread 오브젝트는 만들지만 실제 스레드(OS에서 만들어진 스레드)와는 연결되지 않습니다.

두 번째 생성자는 실제 스레드와 연결된 오브젝트를 생성합니다. 만약 충분한 리소스가 없어서 스레드를 시작할 수 없다면 system_error 오브젝트에 resource_unavailable_try_again 에러코드로 예외를 발생시킵니다.

세 번째 생성자는 다른 thread 오브젝트를 넘겨 받아서 오브젝트를 생성합니다. 인자가 우측 값 참조 이므로 이후에 Other에 연결된 스레드는 Other과 연결이 끊어집니다.

 

아래의 예제를 통해서 스레드를 어떻게 사용하는지 보겠습니다.

 

< 예제. 1 >

#include <thread>

#include <iostream>

 

int main()

{

           std::thread Thread1( [] ()

                        {

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

                                   {

                                          std::cout << "Thread Num : " << i << std::endl;

                                   }

                      } );

 

 

           std::thread Thread2;

           Thread2 = std::thread( [] ()

                        {

                                    for( int i = 10; i < 15; ++i )

                                   {

                                          std::cout << "Thread Num : " << i << std::endl;

                                   }

                         } );

 

           std::thread Thread3 = std::thread( [] ( int nParam )

                        {

                                 for( int i = 20; i < 25; ++i )

                                 {

                                    std::cout << "Thread Parameter : " << nParam << std::endl;

                                 }

                            }, 4 );

 

          

 

           getchar();

           return 0;

}

 

< 결과 >


위 결과를 보면 스레드가 3개 만들어져서 실행된 것을 알 수 있습니다. 그런데 첫 번째 줄에 출력된 결과가 이상하죠? 이것은 공유 객체를 동기화 하지 않아서 발생한 것입니다. 이것은 뒤에 동기화 객체를 설명할 때 고쳐 보겠습니다^^;




ps: 위의 소스는 완벽한 것이 아닙니다. 아마 실행하면 에러가 발생할 것입니다. 이와 관련된 글은 뒤에 적을 글에서 설명할 예정이라서 이번 글의 코드에서는 일부러 조금 불완전한 코드를 사용했습니다.^^;;;


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

올해 2월에 MSHerb Sutter씨는 VC11의 생각보다 빈약한 C++11 기능 지원에 대해서 앞으로 나머지 기능을 업데이트를 통해서 추가해 나갈 것이라고 이야기했습니다.

 

이번에 이 약속이 거짓이 아님을 보여주는 것이 나왔습니다.^^

 

VS 2012 CTP(Community Tech Preview)가 나왔는데 여기에 VS2012에 없는 C++11 기능이 추가 되었습니다.

다운로드 http://www.microsoft.com/en-us/download/details.aspx?id=35515

 

새로 추가된 기능은 아래와 같습니다.

Variadic templates

Uniform initialization and initializer_lists

Delegating constructors

Raw string literals

Explicit conversion operators

Default template arguments for function templates

 

저는 특히 Variadic templatesUniform initialization and initializer_lists가 추가된 것이 무척 반갑습니다. 이후에도 업데이트 버전이 나올 수 있는데 그때는 꼭 constexpr이 구현되면 좋겠습니다. constexpr을 사용하면 기존에 매크로나 템플릿을 사용하여 구현한 부분을 대체하여 더 좋은 성능을 더 쉽게 낼 수 있을 것 같습니다.

 

VS 2012 CTP는 정식 버전은 아니기 때문에 설치 후 사용하기 위해서 약간 손을 봐야 합니다.

프로젝트 속성에서 '일반' -> '플랫폼 툴셋'을 선택하여 ' Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov)'을 선택해야 합니다.

 

좀 더 자세한 설명은 http://blogs.msdn.com/b/vcblog/archive/2012/11/02/visual-c-c-11-and-the-future-of-c.aspx 를 봐 주세요

저작자 표시
신고
by 흥배 2012.11.03 20:45

멀티스레드 프로그래밍 관련 글을 보면 volatile 키워드에 대한 설명을 종종 볼수 있는데 제가 알기로 실제 사용하는 경우는 별로 없을 거라고 생각합니다. 왜냐하면 이미 이 키워드를 사용할 변수를 크리티컬섹션이나 Interlocked 등을 사용하고 있기 때문이죠.

 

지금까지 사용하지 않았다면 계속 사용하지 말고, 사용하고 있다면 다시 한번 생각하기 바랍니다.

 

이유는 volatile 변수는 C++ 언어 사양에서 Memory Barrier 기능을 한다고 명확하게 정의 되어 있지 않기 때문에 만약 Memory Barrier 기능까지 염두에 두고 있다면 사용하고 있는 컴파일러나 플랫폼에서 지원하는지 꼭 확인해야 합니다.

 

Memory Barrier 설명 http://jacking.tistory.com/309

 

 

volatile 키워드를 사용해야 할 곳이 있다면 C++11에서는 atomic 변수를 사용하고, C++03 이전의 컴파일러에서는 각 컴파일러나 플랫폼에서 제공하는 것을 사용하는 것이 좋습니다.

 

 

C++ 언어 규격 문서를 보면

C++03에서는 언어 규격 상 '스레드' 정의가 없다. C++03은 싱글 스레드 환경만을 생각하고 규격을 정의했다. 멀티스레드 관련 부분은 각 컴파일러마다 독자적으로 구현.

 

C++11에서는 '서로 다른 스레드 간에 순서 관계가 정의 되지 않은 메모리 읽기 쓰기 조작은 data race에 의한 알 수 없는 동작을 한다' 라고 되어 있다. C++11에서 volatile 변수는 Memory Barrier 동작을 한다고 명시하지 않고 있다.

 

 

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

아래 코드에서 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

작년 말에 새로운 C++ 표준인 C++11이 나왔고, 아직 C++11을 완벽하게 구현한 컴파일러는 없지만 표준 위원회는 새로운 표준을 위해 작업을 하고 있습니다. 새 표준의 이름은 C++1y 2017년을 목표로 한 이름입니다(과연 될지...-_-).

 

C++1y에 들어갈 새로운 기능들에 대한 후보들을 받고 있는데 20129월의 pre-Portland mailing에 후보들에 설명이 있는데 이 중 제가 흥미롭게 생각한 것들을 몇 개 간단하게 정리해 보았습니다.

 

N3388: Using Asio with C++11

Boost Asio를 소개하고 C++11로 구현하면 어떻게 되는지 이야기 하고 있다. 관련 소스 코드는 Github에 공개.

https://github.com/chriskohlhoff/asio/tree/cpp11-only

 

 

N3389: Urdl: a simple library for accessing web content

Asio OpenSSL를 사용하여 만들어서 Web에서 데이터를 다운로드 하는 라이브러리. 이것은 표준에 넣자는 것은 아니고 Asio를 사용하는 예를 보여주는 것임.

 

 

N3390: Any Library Proposal

Boost Any를 표준으로 제안

 

 

N3395: C++ Stream Mutexes

스트림에 락 기능을 추가

 

 

N3399: Filesystem Proposal

Boost Filesystem 라이브러리의 v3 버전을 적용 

 

 

N3403: Use Cases for Compile-Time Reflection

컴파일 타임 때 사용하는 정적 리플렉션. 아래의 기능 등에 사용할 수 있음

Serialization

Parallel hierarchies

Delegates

Getter/Setter generation

Generating user interfaces to call functions and constructors

 

 

N3406: A proposal to add a utility class to represent optional objects (Revision 2)

Boost optional을 표준으로 제안

 

 

N3408: Parallelizing The Standard Algorithms Library

기존 STL 알고리즘의 병렬 실행 가능한 버전의 추가를 제안

이미 오픈 소스로 만들어져 있는 thrust를 기본으로 한다. http://code.google.com/p/thrust/

 

 

N3409: Strict Fork-Join Parallelism

코어 언어에서 지원을 제안

 

 

N3415: A Database Access Library

데이터 베이스 사용을 위한 라이브러리를 설계할 때 어떤 인터페이스로 만들어야 좋을지 가능성을 보여주는 제안.

 

 

N3419: Vector loops and Parallel Loops

새로운 루프(반복문) 문법으로 벡터 루프와 패럴레 루프 추가를 제안

 

 

N3425: Concurrent Unordered Associative Containers for C++

락 프리로 스레드 세이프한 unordered 컨테이너를 제안

 

 

N3426: Experience with Pre-Parsed Headers

구글의 제안으로 기존의 프리컴파일 헤더를 해결 못하는 문제를 해결하기 위한 것으로 컴파일 중 이미 파싱이 끝난 것은 다시 파싱하지 않고 재 사용하여 컴파일 시간을 단축하는 것

(구글의 경우 소스에서 포함되는 헤더 파일 중 변경이 없는 것이 거의 없어서 프리컴파일 헤더는 의미가 없다고 함)

 

 

N3430: Proposing std::split()

구글의 제안으로 구글이 만들어서 사용해보니 평가가 좋아서 표준 라이브러리에 넣자고 제안

 

 

N3434: C++ Concurrent Queues

 

 

N3446: C++ Mapreduce

구글의 제안으로 Mapreduce 라이브러리를 표준 라이브러리에 넣자는 제안

 

 

대충 이런 이야기들이 나왔고 이중 어떤 것들이 들어갈지 앞으로 표준 위원회에서 많은 토론을 할 것 같습니다.

아마 이게 거의 다 들어간다면 지금까지 한 걸로 봐서는 17년까지는 거의 무리일 것 같네요^^;

 

 

 

 

 

참고 : http://cpplover.blogspot.kr/2012/10/2012-09-pre-portland-mailing.html

 

저작자 표시
신고
by 흥배 2012.10.09 15:41
| 1 2 3 4 5 6 7 |