반응형



a 는 해당 함수의 역함수를 의미한다

asin

Header:
#include <boost/math/complex/asin.hpp>
Synopsis:
template<class T>
std::complex<T> asin(const std::complex<T>& z);

Effects: returns the inverse sine of the complex number z.

Formula: 



Header:
#include <boost/math/complex/acos.hpp>
Synopsis:
template<class T>
std::complex<T> acos(const std::complex<T>& z);

Effects: returns the inverse cosine of the complex number z.

Formula: 


Header:
#include <boost/math/complex/atan.hpp>
Synopsis:
template<class T>
std::complex<T> atan(const std::complex<T>& z);

Effects: returns the inverse tangent of the complex number z.

Formula: 



Header:
#include <boost/math/complex/asinh.hpp>
Synopsis:
template<class T>
std::complex<T> asinh(const std::complex<T>& z);

Effects: returns the inverse hyperbolic sine of the complex number z.

Formula: 




Header:
#include <boost/math/complex/acosh.hpp>
Synopsis:
template<class T>
std::complex<T> acosh(const std::complex<T>& z);

Effects: returns the inverse hyperbolic cosine of the complex number z.

Formula: 





ref : https://www.boost.org/doc/libs/1_67_0/libs/math/doc/html/inverse_complex.html



반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

c+11 과 boost 메모리풀 연동  (0) 2015.03.19
boost :: property_tree  (0) 2014.07.04
xml_parser.hpp, json_parser.hpp  (0) 2014.06.23
boost::intrusive_ptr  (0) 2013.05.13
boost::pool  (0) 2013.05.11
반응형

BLOG main image






#include <list>

#include <hash_set>

#include <hash_map>


#include <boost/pool/object_pool.hpp>

#include <boost/pool/pool_alloc.hpp>



struct nodeInfo{


};




typedef stdext::hash_map<int, nodeInfo , stdext::hash_compare<int> , boost::fast_pool_allocator<int, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex> > hashMapPoolNode;



typedef stdext::hash_set<int, stdext::hash_compare<int> , boost::fast_pool_allocator<int, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex> > hashsetPoolNode;



typedef std::list<int, boost::fast_pool_allocator<int, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex> > listPoolNode;





반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

asin , acos, atan, asinh, acosh  (0) 2018.07.20
boost :: property_tree  (0) 2014.07.04
xml_parser.hpp, json_parser.hpp  (0) 2014.06.23
boost::intrusive_ptr  (0) 2013.05.13
boost::pool  (0) 2013.05.11
반응형

https://sites.google.com/site/boostjp/tips/xml


XML의 읽기 / 쓰기

XML의 읽기, 쓰기에는 Boost Property Tree Library를 사용한다.
Boost.PropertyTree은 트리 구조의 일반 속성 관리를위한 라이브러리 XML, JSON, INI 파일 등의 통일적인 접근 방법을 제공한다.

여기에서는 Boost.PropertyTree를 사용하여 XML 파일의 읽기와 쓰기를 소개한다.

XML 요소의로드

XML 가져 오기에는 boost :: property_tree :: read_xml () 함수를 사용한다.
이 함수를 사용하려면 <boost/property_tree/xml_parser.hpp>을 포함한다.

다음 XML 파일을 읽어 보자.

data.xml
<? xml version = "1.0"encoding = "utf-8"?>

<root>
    <str> Hello </ str>
    <values​​>
        <value> 1 </ value>
        <value> 2 </ value>
        <value> 3 </ value>
    </ values​​>
</ root>


# include <iostream>
# include <string>
# include <boost/property_tree/ptree.hpp>
# include <boost/property_tree/xml_parser.hpp>
# include <boost/foreach.hpp>
# include <boost/lexical_cast.hpp>

int main ()
{
    using namespace boost :: property_tree;

    ptree pt;
    read_xml ( "data.xml", pt);

    if (boost :: optional <std::string> str = pt. get_optional <std::string> ( "root.str") ) {
        std :: cout << str.get () << std :: endl;
    }
    else {
        std :: cout << "root.str is nothing"<< std :: endl;
    }

    BOOST_FOREACH (const ptree :: value_type & child, pt.get_child ( "root.values") ) {
        const int value = boost :: lexical_cast <int> (child.second.data ());
        std :: cout << value << std :: endl;
    }
}

실행 결과 :
Hello
1
2
3

먼저 root / str 요소를 얻으려면 XML이로드 된 boost :: property_tree : ptree에 대해 다음과 같이 지정한다 :

boost :: optional <std::string> str = pt.get_optional <std::string> ( " root.str ")


요소 액세스 경로 지정은 XPath 대신 마침표 액세스한다.
get_optional 함수는 지정된 형식으로 변환 된 요소가 반환된다. 요소의 취득에 실패했을 경우는 boost :: optional 잘못된 값이 반환된다.



그런 다음 root / values​​ / value 요소를 열거하려면 boost :: property_tree :: ptree 대해 get_child () 함수에서 경로 지정 하위 트리를 검색한다. 취득한 자식 트리를 BOOST_FOREACH를 반복하고 문자열 (std :: string)로 만들어지는 각 value 요소를 int로 변환하고 있어요.


BOOST_FOREACH (const ptree :: value_type & child, pt. get_child ( "root.values")


속성의 취득

XML 요소의 속성을 가져 오려면 "<xmlattr>"라는 특수한 요소 이름을 경로 지정함으로써 얻을 수있다. 
다음은 속성이있는 XML을로드 예이다 :

data.xml
<? xml version = "1.0"encoding = "utf-8"?>

<root>
    <data id="3" name="str"​​/>
</ root>

# include <iostream>
# include <string>
# include <boost/property_tree/ptree.hpp>
# include <boost/property_tree/xml_parser.hpp>

int main ()
{
    using namespace boost :: property_tree;

    ptree pt;
    read_xml ( "data.xml", pt);

    if (boost :: optional <int> id = pt.get_optional <int> ( "root.data. <xmlattr> . id ")) {
        std :: cout << id.get () << std :: endl;
    }
    else {
        std :: cout << "id is nothing"<< std :: endl;
    }

    if (boost :: optional <std::string> name =
            pt.get_optional <std::string> ( "root.data. <xmlattr>. name")) {
        std :: cout << name.get () << std :: endl;
    }
    else {
        std :: cout << "name is nothing"<< std :: endl;
    }
}

실행 결과 :
3
str


XML 작성

XML을 쓰려면 요소를 추가하기 위해 boost :: property_tree :: ptree의 add () 멤버 함수를 사용하여 put () 멤버 함수에서 값을 설정한다.
저장은 boost :: property_tree :: write_xml에 파일 이름과 ptree을 지정한다.

# include <vector>
# include <string>
# include <boost/property_tree/ptree.hpp>
# include <boost/property_tree/xml_parser.hpp>
# include <boost/foreach.hpp>

struct Book {
    std :: string title;
    std :: string author;

    Book () {}
    Book (const Book & other)
        : title (other.title), author (other.author) {}

    Book (const std :: string & title, const std :: string & author)
        : title (title), author (author) {}
};

int main ()
{
    std :: vector <Book> books;
    books.reserve (2);
    books.push_back (Book ( "D & E", "Bjarne Stroustrup"));
    books.push_back (Book ( "MC + + D", "Andrei, Alexandrescu"));

    using boost :: property_tree :: ptree;

    ptree pt;
    BOOST_FOREACH (const Book & book, books) {
        ptree & child = pt.add ( "bookList.book", "");
        child.put ( "<xmlattr>. title"book.title);
        child.put ( "<xmlattr>. author"book.author);
    }

    using namespace boost :: property_tree :: xml_parser;
    const int indent = 2;
    write_xml ( "book.xml", pt std :: locale ()
        xml_writer_make_settings ( '', indent, widen <char> ( "utf-8")));
}

book.xml
<? xml version = "1.0"encoding = "utf-8"?>
<bookList>
  <book title="D&E" author="Bjarne Stroustrup"/>
  <book title="MC++D" author="Andrei Alexandrescu"/>
</ bookList>

write_xml는 제 3 인수 이후를 생략하면 들여 쓰기와 줄 바꿈이 생략된다.
xml_writer_make_settings을 사용하여 들여 쓰기 및 인코딩을 설정할 수있다.






출처 : http://kindtis.tistory.com/358



JSON 포맷 사용을 위해 boost의 property_tree를 사용하기로 했습니다. 실제로 사용해본 결과 그 간편함이 XML과 tinyXML 조합 때 보다 훨씬 쾌적했습니다.  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- JSON 예제 파일 -->
{
    "String": "테스트",
    "Number": 12345,
    "Boolen": true,
    "StrArray": [ "테스트1", "테스트2" ],
    "NumArray": [ 1, 2, 3, 4, 5 ],
    "SubValue" :
    {
    "SubString": "서브테스트",
    "SubNumber": 67890,
    "SubBoolen": false
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// JSON 입력 테스트
EXPECT_TRUE( exists( "test.json" ) );
 
wptree pt;
read_json( "test.json", pt, locale("kor") );
 
wstring strTest = pt.get<wstring>( L"String" );
EXPECT_TRUE( 0 == strTest.compare( L"테스트" ) );
 
int numTest = pt.get( L"Number", 0 );
EXPECT_TRUE( 12345 == numTest );
 
bool boolTest = pt.get( L"Boolen", false );
EXPECT_TRUE( boolTest );
 
vector<wstring> strArrayTest;
BOOST_FOREACH( wptree::value_type &v, pt.get_child( L"StrArray" ) )
{
    strArrayTest.push_back( v.second.data() );
}
EXPECT_TRUE( 2 == (int)strArrayTest.size() );
     
vector<wstring> numArrayTest;
BOOST_FOREACH( wptree::value_type &v, pt.get_child( L"NumArray" ) )
{
    numArrayTest.push_back( v.second.data() );
}
EXPECT_TRUE( 5 == (int)numArrayTest.size() );
 
wstring strSubTest = pt.get<wstring>( L"SubValue.SubString" );
EXPECT_TRUE( 0 == strSubTest.compare( L"서브테스트" ) );
 
int numSubTest = pt.get( L"SubValue.SubNumber", 0 );
EXPECT_TRUE( 67890 == numSubTest );
 
bool boolSubTest = pt.get( L"SubValue.SubBoolen", true );
EXPECT_TRUE( false == boolSubTest );

위의 샘플 코드를 보시면 아시겠지만 굉장히 직관적입니다. 읽고, 가져다 쓰기만 하면 되죠. 타입도 대부분 알아서 정해줍니다. 다만, 배열이 조금 문제인데 이것이 무조건 문자열로만 읽는 것 같습니다. ( 해결법 아시는 분은 자비 점... )

문제는 좀더 있습니다. 특히 쓰기가 문제입니다. boost 1.46.1 버전 기준으로 property_tree를 이용해 JSON 파일 쓰기를 하면, 모든 값들이 문자열로만 저장이 됩니다. int 형이나 bool 형 상관없이 무조건 문자열로만 저장입니다. 읽기와는 전혀 딴판이죠. 그래서 구글링으로 해결책을 찾아보던 중 property_tree의 소스를 조금 수정 하는 것으로 이 문제를 해결할 수 있었습니다.

json_parser_write.hpp의 52 줄 부분을 보시면 밑의 스샷과 같은 부분이 있습니다.
1
2
3
4
5
6
7
8
// Value or object or array
if (indent > 0 && pt.empty())
{
    // Write value
    Str data = create_escapes(pt.template get_value <Str>());
    //stream << Ch('"') << data << Ch('"');
    stream << data;
}

중간에 제가 주석을 쳐놓은 부분이 있습니다. 이 부분이 모든 값을 " "로 감싸어 문자열로 만들어 버리는 부분입니다. 이 부분을 주석 처리하면 문자열이 아닌 값으로 저장이 되죠. 하지만 이렇게만 두면 문자열로 저장하고 싶은 부분도 " " 감싸짐 없이 그대로 저장되기때문에 파싱 할때 오류가 나게 됩니다.

문자열은 예외를 둬야 하죠. 다행히 propert_tree는 값을 지정할때 Translator를 지정할 수 있습니다. 이 기능을 이용해 문자열에만 " "를 감싸 줄 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
struct tr
{
    typedef T internal_type;
    typedef T external_type;
 
    boost::optional<T> get_value(const T &v) { return  v.substr(1, v.size() - 2); }
    boost::optional<T> put_value(const T &v) { return L'"' + v + L'"'; }
};
 
wptree wPt;
wPt.put( L"StringTest", L"Test", tr<wstring>() );
wPt.put( L"NumTest", 1234 );
wPt.put( L"BoolenTest", false );
write_json( "writeTest.json", wPt );
1
2
3
4
5
6
<!-- 출력 결과물 -->
{
    "StringTest": "Test",
    "NumTest": 1234,
    "BoolenTest": false
}
이제 문자열과 값이 구분되어 잘 나옵니다. 하지만 아직 한가지 문제가 더 남았습니다. 바로 한글!! property_tree는 기본적으로 한글 출력이 안됩니다. 읽는 거는 locale("kor") 옵션을 주고, 읽기가 가능하지만 쓰기에서는 locale("kor") 옵션을 준다고 해도 한글 출력이 안됩니다. json_parser_write.hpp 파일 내부를 보면 그 이유를 알수 있습니다.
1
2
3
4
5
6
// This assumes an ASCII superset. But so does everything in PTree.
// We escape everything outside ASCII, because this code can't
// handle high unicode characters.
if (*b == 0x20 || *b == 0x21 || (*b >= 0x23 && *b <= 0x2E) ||
    (*b >= 0x30 && *b <= 0x5B) || (*b >= 0x5D && *b <= 0xFF))
    result += *b;
보시면 문자열 범위에서 영어권 문자열표를 제외한 특수문자는 모조리 제외되어있습니다. 이 때문에 한글을 써도 제대로 출력이 안되는 것 입니다. 여기에 한글 문자열 범위를 추가해 줍니다.
( 참고 : http://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_A000~AFFF )

수정 한 후에는 wraite_json에 locale("kor") 옵션을 주고, 쓰기를 실행 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
struct tr
{
    typedef T internal_type;
    typedef T external_type;
 
    boost::optional<T> get_value(const T &v) { return  v.substr(1, v.size() - 2); }
    boost::optional<T> put_value(const T &v) { return L'"' + v + L'"'; }
};
 
wptree wPt;
wPt.put( L"StringTest", L"한글 테스트", tr<wstring>() );
wPt.put( L"NumTest", 1234 );
wPt.put( L"BoolenTest", false );
write_json( "writeTest.json", wPt, locale("kor") );
1
2
3
4
5
6
<!-- 출력 결과물 -->
{
    "StringTest": "한글 테스트",
    "NumTest": 1234,
    "BoolenTest": false
}
이제 한글도 잘 나오게 되었습니다.

만세~

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

asin , acos, atan, asinh, acosh  (0) 2018.07.20
c+11 과 boost 메모리풀 연동  (0) 2015.03.19
xml_parser.hpp, json_parser.hpp  (0) 2014.06.23
boost::intrusive_ptr  (0) 2013.05.13
boost::pool  (0) 2013.05.11
반응형

#include <boost/property_tree/ptree.hpp>

#include <boost/property_tree/json_parser.hpp>

#include <boost/foreach.hpp>



xml일 경우 




boost 쓰실때 포함해야 할 헤더 입니다. json_parser.hpp 를 xml_parser.hpp로 고치시면 됩니다.



아래 글 출처 http://kindtis.tistory.com/358


JSON 포맷 사용을 위해 boostproperty_tree를 사용하기로 했습니다. 실제로 사용해본 결과 그 간편함이 XMLtinyXML 조합 때 보다 훨씬 쾌적했습니다.  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- JSON 예제 파일 -->
{
    "String": "테스트",
    "Number": 12345,
    "Boolen": true,
    "StrArray": [ "테스트1", "테스트2" ],
    "NumArray": [ 1, 2, 3, 4, 5 ],
    "SubValue" :
    {
    "SubString": "서브테스트",
    "SubNumber": 67890,
    "SubBoolen": false
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// JSON 입력 테스트
EXPECT_TRUE( exists( "test.json" ) );
 
wptree pt;
read_json( "test.json", pt, locale("kor") );
 
wstring strTest = pt.get<wstring>( L"String" );
EXPECT_TRUE( 0 == strTest.compare( L"테스트" ) );
 
int numTest = pt.get( L"Number", 0 );
EXPECT_TRUE( 12345 == numTest );
 
bool boolTest = pt.get( L"Boolen", false );
EXPECT_TRUE( boolTest );
 
vector<wstring> strArrayTest;
BOOST_FOREACH( wptree::value_type &v, pt.get_child( L"StrArray" ) )
{
    strArrayTest.push_back( v.second.data() );
}
EXPECT_TRUE( 2 == (int)strArrayTest.size() );
     
vector<wstring> numArrayTest;
BOOST_FOREACH( wptree::value_type &v, pt.get_child( L"NumArray" ) )
{
    numArrayTest.push_back( v.second.data() );
}
EXPECT_TRUE( 5 == (int)numArrayTest.size() );
 
wstring strSubTest = pt.get<wstring>( L"SubValue.SubString" );
EXPECT_TRUE( 0 == strSubTest.compare( L"서브테스트" ) );
 
int numSubTest = pt.get( L"SubValue.SubNumber", 0 );
EXPECT_TRUE( 67890 == numSubTest );
 
bool boolSubTest = pt.get( L"SubValue.SubBoolen", true );
EXPECT_TRUE( false == boolSubTest );


위의 샘플 코드를 보시면 아시겠지만 굉장히 직관적입니다. 읽고, 가져다 쓰기만 하면 되죠. 타입도 대부분 알아서 정해줍니다. 다만, 배열이 조금 문제인데 이것이 무조건 문자열로만 읽는 것 같습니다. ( 해결법 아시는 분은 자비 점... )

문제는 좀더 있습니다. 특히 쓰기가 문제입니다. boost 1.46.1 버전 기준으로 property_tree를 이용해 JSON 파일 쓰기를 하면, 모든 값들이 문자열로만 저장이 됩니다. int 형이나 bool 형 상관없이 무조건 문자열로만 저장입니다. 읽기와는 전혀 딴판이죠. 그래서 구글링으로 해결책을 찾아보던 중 property_tree의 소스를 조금 수정 하는 것으로 이 문제를 해결할 수 있었습니다.

json_parser_write.hpp52 줄 부분을 보시면 밑의 스샷과 같은 부분이 있습니다.

1
2
3
4
5
6
7
8
// Value or object or array
if (indent > 0 && pt.empty())
{
    // Write value
    Str data = create_escapes(pt.template get_value <Str>());
    //stream << Ch('"') << data << Ch('"');
    stream << data;
}


중간에 제가 주석을 쳐놓은 부분이 있습니다. 이 부분이 모든 값을 " "로 감싸어 문자열로 만들어 버리는 부분입니다. 이 부분을 주석 처리하면 문자열이 아닌 값으로 저장이 되죠. 하지만 이렇게만 두면 문자열로 저장하고 싶은 부분도 " " 감싸짐 없이 그대로 저장되기때문에 파싱 할때 오류가 나게 됩니다.

문자열은 예외를 둬야 하죠. 다행히 propert_tree는 값을 지정할때 Translator를 지정할 수 있습니다. 이 기능을 이용해 문자열에만 " "를 감싸 줄 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
struct tr
{
    typedef T internal_type;
    typedef T external_type;
 
    boost::optional<T> get_value(const T &v) { return  v.substr(1, v.size() - 2); }
    boost::optional<T> put_value(const T &v) { return L'"' + v + L'"'; }
};
 
wptree wPt;
wPt.put( L"StringTest", L"Test", tr<wstring>() );
wPt.put( L"NumTest", 1234 );
wPt.put( L"BoolenTest", false );
write_json( "writeTest.json", wPt );
1
2
3
4
5
6
<!-- 출력 결과물 -->
{
    "StringTest": "Test",
    "NumTest": 1234,
    "BoolenTest": false
}

이제 문자열과 값이 구분되어 잘 나옵니다. 하지만 아직 한가지 문제가 더 남았습니다. 바로 한글!! property_tree는 기본적으로 한글 출력이 안됩니다. 읽는 거는 locale("kor") 옵션을 주고, 읽기가 가능하지만 쓰기에서는 locale("kor") 옵션을 준다고 해도 한글 출력이 안됩니다. json_parser_write.hpp 파일 내부를 보면 그 이유를 알수 있습니다.

1
2
3
4
5
6
// This assumes an ASCII superset. But so does everything in PTree.
// We escape everything outside ASCII, because this code can't
// handle high unicode characters.
if (*b == 0x20 || *b == 0x21 || (*b >= 0x23 && *b <= 0x2E) ||
    (*b >= 0x30 && *b <= 0x5B) || (*b >= 0x5D && *b <= 0xFF))
    result += *b;

보시면 문자열 범위에서 영어권 문자열표를 제외한 특수문자는 모조리 제외되어있습니다. 이 때문에 한글을 써도 제대로 출력이 안되는 것 입니다. 여기에 한글 문자열 범위를 추가해 줍니다.
( 참고 : http://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_A000~AFFF )

수정 한 후에는 wraite_json에 locale("kor") 옵션을 주고, 쓰기를 실행 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
struct tr
{
    typedef T internal_type;
    typedef T external_type;
 
    boost::optional<T> get_value(const T &v) { return  v.substr(1, v.size() - 2); }
    boost::optional<T> put_value(const T &v) { return L'"' + v + L'"'; }
};
 
wptree wPt;
wPt.put( L"StringTest", L"한글 테스트", tr<wstring>() );
wPt.put( L"NumTest", 1234 );
wPt.put( L"BoolenTest", false );
write_json( "writeTest.json", wPt, locale("kor") );
1
2
3
4
5
6
<!-- 출력 결과물 -->
{
    "StringTest": "한글 테스트",
    "NumTest": 1234,
    "BoolenTest": false
}

이제 한글도 잘 나오게 되었습니다.
만세~

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

c+11 과 boost 메모리풀 연동  (0) 2015.03.19
boost :: property_tree  (0) 2014.07.04
boost::intrusive_ptr  (0) 2013.05.13
boost::pool  (0) 2013.05.11
boost::dynamic_bitset  (0) 2013.03.08
반응형

http://blog.naver.com/cyberyanne/40107196465


다음과 같은 코드에서 Smart Pointer를 사용할 수 있을까?


class  Object
{
public:
      boost::shared_ptr<Object>  methodA(int value)
      {
           if(value == 0 )
               return this;  <-- 문제 코드.
           else
               return member;
       }

private:
       boost::shared_ptr<Object>    member;
}

위 코드에서 methodA(value)는 입력 매개 변수값에 따라 자기 자신을 리턴하거나, 
아니면 자기가 가지고 있는 member의 값을 리턴한다. member도 smart pointer로 
정의되어 있죠.

자, 이 경우 member를 리턴하는 것은 별 문제가 안됩니다. 
문제가 되는 경우는 자기 자신을 리턴해야 하는 경우입니다.

{
       boost::shared_ptr<Object>   pObj( new Object ), pObj2;
       
       pObj2 = pObj->methodA(0);
}

case 1. methodA()에서 컴파일 에러를 막기 위해서 boost::shared_ptr<Object>(this) 값을 
           리턴하는 경우를 생각해봅시다. 이렇게 되면, 위 App code에서 pObj, pObj2가 
           같은 오브젝트를 가리키는 서로 다른 2개의 smart pointer가 됩니다. 따라서
           메모리 객체가 2번 지워지는 에러가 발생합니다.

case 2. 그렇다고 "this"를 그대로 리턴할 수도 없습니다. 컴파일 에러가 나니까요.

case 3. Object가 스스로를 가리키는 smart pointer "self"를 가지게 하고, 이 값을 methodA()를
           통해서 리턴할 수도 있습니다. 하지만 이렇게 되면 해당 오브젝트는 자기 순환 참조를 하게
           되어 메모리 릭으로 남습니다. (use_count가 0이 될 수가 없습니다.)

이 문제를 해결하기 위해서 이리저리 자료를 찾아보고, 고민을 해봤는데, 
결론은 "shared_ptr<T>은 사용할 수 없다" 입니다.

대신, boost::intrusive_ptr<T>을 사용하면 이 문제를 해결할 수 있습니다.
intrusive_ptr<T>는 기본적으로 shared_ptr<T>와 사용법은 비슷하나 Reference Count를
메모리 객체가 직접 관리해야 하는 점이 다릅니다. shared_ptr<T>의 경우, 포인터를 감싸는
별도의 구조체를 자동으로 생성하고 거기에서 reference count를 관리하는데, intrusive_ptr<T>은
Object가 제공하는 Reference Counter 인터페이스를 이용합니다. 








http://kksuny.tistory.com/15


ntrusive_ptr 은 shared_ptr 과 마찬가지로 참조 카운팅 방식의 스마트 포인터다.

그러나 intrusive_ptr은 reference count 를 스마트 포인터에서 관리되는 객체에서 직접 관리한다.

intrusive_ptr 객체는 intrusive_ptr_add_ref 함수를 이용해 reference count 를 증가시키고

반대로 intrusive_ptr_release 함수로 감소시킨다.

intrusive_ptr_release 함수 에서는 reference count가 0이 될때 관리되는 객체를 파괴시켜야 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class MyClass;
void intrusive_ptr_add_ref(MyClass* p);
void intrusive_ptr_release(MyClass* p);
 
class MyClass
{
public:
    MyClass():m_refCount(0){}
    ~MyClass(){}
 
    friend void intrusive_ptr_add_ref(MyClass* p)
    {
        p->m_refCount++;
    }
 
    friend void intrusive_ptr_release(MyClass* p)
    {
        if(--(p->m_refCount) <= 0)
        {
            delete p;
        }
    }
private:
    long m_refCount;
};

intrusive_ptr 을 사용하는 주된 이유:

  • Some existing frameworks or OSes provide objects with embedded reference counts;
  • The memory footprint of intrusive_ptr is the same as the corresponding raw pointer;
  • intrusive_ptr<T> can be constructed from an arbitrary raw pointer of type T *.

shared_ptr보다 intrusive_ptr이 사용 요구에 맞는 것인지 명확하지 않다면 일반적으로, 먼저 shared_ptr 기반의 디자인을 시도한다.







http://blog.naver.com/cyberyanne/40107424728



boost::intrusive_ptr<T>는 boost 패키지에서 제공하는 또 다른 형태의 Smart Pointer입니다.
이전 글에서 설명한 boost::shared_ptr<T>는 smart pointer가 스스로 reference count를 관리했지만,
intrusive_ptr<T>는 reference count 관리를 타겟 메모리 객체에 맡깁니다. 즉, Reference count는
메모리 관리의 대상이 되는 객체에서 직접하고, intrusive_ptr<T>는 그 객체가 제공하는 Reference
count 기능을 빌려쓰는 겁니다. 그러면 메모리 객체와 intrusive_ptr<T> 사이를 연결해 주는
매개체가 있어야 겠죠. intrusive_ptr<T>는 다음의 두 함수를 통해 메모리 객체를 관리합니다.

void    intrusive_ptr_add_ref(Object *a_pObject) 
void    intrusive_ptr_release(Object *a_pObject)

예를 하나 들어보죠.
아래 클래스는 관리의 대상이 되는 Object를 정의합니다. 
보시면 Reference Count 인터페이스가 정의되어 있습니다.

class Object 
{
public:
// Constructor.
Object(void) : m_iRefCount(0) {};
virtual ~Object(void) {};

// Ref count manager.
void    inc_ref(void) { m_iRefCount++; };
void    dec_ref(void) { m_iRefCount--; };
void    get_ref(void) { return m_iRefCount; };

private:
int      m_iRefCount;
}

boost::intrusive_ptr<T>는 이전에 설명한 shared_ptr<T>와 동일한 방식으로 사용합니다.

{
boost::intrusive_ptr<Object>       sp1 = boost_intrusive_ptr<Object>(new Object);
boost::intrusive_ptr<Object>       sp2;

sp2 = sp1;
...
}

그리고 intrusive_ptr<T>와 Object를 연결하는 두 함수는 다음과 같이 제공되어야 합니다.

void     intrusive_ptr_add_ref(Object *a_pObject)
{
a_pObject->inc_ref();
}

void     intrusive_ptr_release(Object *a_pObject)
{
a_pObject->dec_ref();
if( a_pObject->get_ref() <= 0 )
delete a_pObject;
}

boost::intrusive_ptr<T>는 타겟 객체에 Reference count를 증가시킬 때, intrusive_ptr_add_ref()
함수를 호출하고, Reference count를 감소시킬 때 intrusive_ptr_release()를 호출합니다. 따라서
이 두 함수를 사용자가 제공해 주지 않으면 링크 에러가 발생하게 됩니다.

intrusive_ptr<T>는 어떤 경우에 유용할까요?

1. 기존 코드에 smart pointer를 입히는 경우입니다. 이미 예전 코드에 Reference count
   메커니즘이 적용되어 있는 경우, intrusive_ptr<T>을 이용하여 쉽게 코드를 refactoring
   할 수 있습니다.

2. Object가 자기 자신(this)에 대한 smart pointer를 리턴해야 하는 경우입니다.
    shared_ptr<T>는 이 상황을 처리하지 못합니다. (이전 글 참조)

3. ...

boost 패키지 문서에서는 가급적이면 shared_ptr<T>를 사용하라고 권고하고 있습니다.
하지만, 위에서 나열한 경우라면 intrusive_ptr<T>를 사용하는 것이 좀 더 나을 수 있습니다.

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost :: property_tree  (0) 2014.07.04
xml_parser.hpp, json_parser.hpp  (0) 2014.06.23
boost::pool  (0) 2013.05.11
boost::dynamic_bitset  (0) 2013.03.08
boost::boost::unordered_map, unordered_set  (0) 2013.03.02
반응형



필요한 헤더:
<boost/pool/pool.hpp>,
<boost/pool/object_pool.hpp>,
<boost/pool/singleton_pool.hpp> 등. 사용한다template에 따라.
기능:
고정 사이즈의 고속 메모리 할당

#include <iostream>
#include <boost/pool/pool.hpp>
#include <boost/pool/object_pool.hpp>
using namespace std;


struct Abc
{
  Abc()  { static int no=0; cout << "Abc() :" << (m_no=++no) << endl; }
  ~Abc() { cout << "~Abc():" << m_no << endl; }
  int m_no;
};

int main()
{
  {
    // sizeof(int)아르바이트 전용 allocater
    boost::pool<> p( sizeof(int) );
    int* x = (int*)p.malloc();
    int* y = (int*)p.malloc();
    int* z = (int*)p.malloc();
    *x = 10;
    p.free(z); // 명시적으로free

    // free하지 않고라고도pool오브젝트의 수명과 동시에 해방된다
  }

  {
    // Abc전용 allocater
    boost::object_pool<Abc> p;
    Abc* x = p.construct();
    Abc* y = p.construct();
    Abc* z = p.construct();
    p.destroy(y);// 명시적으로 소멸자 호출

    // destroy하지 않고라고도pool오브젝트의 수명과 동시에 해방된다
  }

  return 0;
}

출력
Abc() :1
Abc() :2
Abc() :3
~Abc():2
~Abc():1
~Abc():3



http://cafe.naver.com/cafec/271959


일단 우리가 쓸 범용적인 메모리 풀은
boost/pool/object_pool.hpp 에 있습니다.
템플릿을 통해 객체를 받고 자동으로 생성자와 소멸자도 호출해줍니다.

예제1
class Something
{
    int v;
public:
    Something(){v=rand()%100+1;cout<<"생성"<<v<<endl; }
    ~Something(){cout<<"소멸"<<v<<endl;}
    void Print(void){cout<<v<<endl;}
};


int main(void)
{
    boost::object_pool<Something> memory_pool(10); //이 시점에서 Something 500개가 할당되지 않습니다.
    Something* trash = memory_pool.construct(); // 이 시점에서 할당됩니다.
    for(int i=0;i<5;i++)
    {
        Something* val = memory_pool.construct();
        val->Print();
        memory_pool.destroy(val);
    }
    return 0;
}
일단 construct멤버함수로 메모리풀에 있는 자원을 쓸 수 있습니다.
destroy로 해제 할 수 있습니다. 
object_pool 객체는 메모리풀이 생성될때 해당 갯수의 메모리를 할당하지 않고, 한번 construct할 때 할당한다고 합니다.
그래서 아무거나 한번 생성했습니다.
프로그램 돌려보시면 아시겠지만, 맨 마지막에 trash가 해제됩니다. 프로그래머가 해제를 하지 않아도 construct해준것은 destory해줍니다.

두번째 예제에서는 실행시간 비교...를 해보겠습니다.
시간측정을 위해서 #include <boost/chrono.hpp> 를 해줍시다.

    auto start_mempool = boost::chrono::system_clock::now();
    boost::object_pool<Something> memory_pool(10000); //이 시점에서 Something 500개가 할당되지 않습니다.
    Something* trash = memory_pool.construct(); // 이 시점에서 할당됩니다.
    for(int i=0;i<10000;i++)
    {
        Something* val = memory_pool.construct();
        val->Print();
        memory_pool.destroy(val);
    }
    auto end_mempool = boost::chrono::system_clock::now();
    auto duration = end_mempool - start_mempool;
    

    auto start_alloc = boost::chrono::system_clock::now();
    for(int i=0;i<10000;i++)
    {
        Something* val = new Something;
        val->Print();
        delete val;
    }
    auto end_alloc = boost::chrono::system_clock::now();
    auto duration_alloc = end_alloc - start_alloc;

    cout<<"메모리풀"<<duration<<endl;
    cout<<"무식하게 할당"<<duration_alloc<<endl;
    system("pause");
    return 0;




메모리풀 : 약 31초
무식하게 할당 : 약 35초

더 많이 돌리면 차이가 더 나겠죠.






http://blog.naver.com/sorkelf/40135434878



Pool.cpp



고정크기의 작은 블럭(chunk)들을 할당할때 고속으로 작동하는 메모리 할당 관리자

로써 메모리사용시 속도문제와 단편화 문제를 해결하기위해 사용되는 라이브러리이다.

현재 할당된 크기의 2배씩 커지는 특징이 있다


boost::pool  <- 기본 Pool 인터페이스


boost::object_pool  <- 객체 기반의 Pool 인터페이스


boost::singleton_pool <- 정적 기반의 thread safe singleton으로서의 기본 Pool 인터페이스


boost::pool_alloc     <-  singleton_pool에 기초를 둔 표준 allocator 인터페이스 


예제)








결과)





boost의 share_ptr을 사용할때 일반적으로


typedef boost::shared_ptr<Myclass> SharedPtr;

SharedPtr ptr  = SharedPtr(new Myclass); 


위와 같은 방식의 힙의 동적 메모리 할당을 사용하나


new와 delete를 자주 하는 경우에는 메모리 단편화를 몰고 오고 


단편화들로 인한 캐쉬히트들을 떨어뜨리며 그것은 즉슨 


시스템의 퍼포먼스를 떨어트리는 결과를 가져오게 된다


이럴 때 boost::pool을 사용하면 상당히 좋다 -ㅅ-


특히 릴리즈모드에서 탁월한 효과를 볼수 있다.

[출처] boost::pool|작성자 풍풍풍










http://blog.naver.com/sorkelf/40154614484


std::allocator VS boost::fast_pool_allcator (pool_allcator)






boost::pool 관련된 내용을 찾아 돌아다니던 중..( 왜 돌아다녔지..-_-)


pool_allocator - 메모리 공간을 특정영역 만큼 할당에서 특정 메모리영역 에서 데이터를

insert 및 delete 처리.. vector에 사용


fast_pool_allocator - 메모리 공간을 할당하지 않으나 이전에 메모리를 할당 하였을 경우

이전 메모리 주소의 근처에 있는 메모리 주소를 할당한다 list, set, map에 사용


내용이 있어얼마나 많이 빨라지나 테스트를 해본 결과...


list에서는 fast_pool_allocator를 쓰면 나름 속도가 빨라지지만

set은 거기서 거기였고.. vector는 처음 할당할때 느려졌다 (reserve 하면 그나마 제 속도...)


아래는 테스트 코드이다..

(AMD Cpu일 경우 시간이 잘 안맞는다는 이야기가 있어서.. ::timeGetTime()으로 대체..)


#include <iostream>
#include <Windows.h>
#include <list>
#include <vector>
#include <set>
#include <boost/pool/pool_alloc.hpp>
#include <boost/unordered_set.hpp>
#include <MMSystem.h>
#pragma comment(lib,"winmm.lib")

using namespace std;

//#define _USE_NVIDIA //AMD일 경우 시간이 약간 안맞는다..
#define _USE_BOOST_POOL         //BOOST_POOL 사용
#define _USE_NULL_MUTEX         //Null Mutex 사용
//#define _USE_HASH_SET //boost/unordered_set 사용


#ifdef _USE_NVIDIA
    double pcFreq = 0.0;
    __int64 CounterStart = 0;
#else
    DWORD startTime;
    DWORD endTime;
#endif

#ifdef _USE_BOOST_POOL

        #ifdef _USE_NULL_MUTEX
            typedef std::list<int, boost::fast_pool_allocator <int, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex> > BOOST_POOL_LIST;

            typedef std::vector<int, boost::pool_allocator <int, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex> > BOOST_POOL_VECTOR;

            typedef boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
                boost::fast_pool_allocator<int, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex> > BOOST_POOL_SET;
    #else
        typedef std::list<int, boost::fast_pool_allocator <int, boost::default_user_allocator_new_delete, boost::details::pool::default_mutex> > BOOST_POOL_LIST;

        typedef std::vector<int, boost::pool_allocator <int, boost::default_user_allocator_new_delete, boost::details::pool::default_mutex> > BOOST_POOL_VECTOR;

        typedef boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
            boost::fast_pool_allocator<int, boost::default_user_allocator_new_delete, boost::details::pool::default_mutex> > BOOST_POOL_SET;
    #endif
#endif

void StartCounter();
double GetCounter();

#define TEST_TIME_NUMBER 1000
#define TEST_ITERATOR_NUMBER 80000

int main()
{
    #ifdef _USE_BOOST_POOL
        cout << "------- USE_BOOST_POOL -------" <<endl;

        #ifdef _USE_NULL_MUTEX
                cout << "------- USE_NULL_MUTEX -------" <<endl;
        #else
                cout << "------- USE_DEFAULT_MUTEX-------" <<endl;
        #endif
    #else
        cout << "------- std::list -------" <<endl;
        cout << "------- std::vector -------" <<endl;
        #ifdef _USE_HASH_SET
            cout << "------- boost::unordered_set -------" <<endl;
        #else
            cout << "------- std::set-------" <<endl;
        #endif
    #endif

    cout << endl;

    //List
    {
        #ifdef _USE_BOOST_POOL
                BOOST_POOL_LIST testContainer;
        #else
                std::list<int> testContainer;
        #endif

        StartCounter();

        for(int iTestTime = 0; iTestTime< TEST_TIME_NUMBER; ++iTestTime)
        {
            for(int iIterateConut = 0; iIterateConut< TEST_ITERATOR_NUMBER; ++iIterateConut)
            {
                testContainer.push_back(iIterateConut);
            }

            for(int iIterateConut = 0; iIterateConut< TEST_ITERATOR_NUMBER; ++iIterateConut)
            {
                testContainer.pop_back();
            }
        }

        //결과 출력
        cout << "list(Push, Pop) : " << GetCounter() <<endl;
    }

    //Vector
    {
        #ifdef _USE_BOOST_POOL
                BOOST_POOL_VECTOR testContainer;
        #else
                std::vector<int> testContainer;
        #endif

        testContainer.reserve(TEST_TIME_NUMBER* TEST_ITERATOR_NUMBER);

        StartCounter();

        for(int iTestTime = 0; iTestTime< TEST_TIME_NUMBER; ++iTestTime)
        {
            for(int iIterateConut = 0; iIterateConut< TEST_ITERATOR_NUMBER; ++iIterateConut)
            {
                testContainer.push_back(iIterateConut);
            }

            for(int iIterateConut = 0; iIterateConut< TEST_ITERATOR_NUMBER; ++iIterateConut)
            {
                testContainer.pop_back();
            }
        }

        //결과 출력
        cout << "vector(Push, Pop) : " << GetCounter() <<endl;

    }

    //Set

    {
        #ifdef _USE_BOOST_POOL
                BOOST_POOL_SET testContainer;
        #else
            #ifdef _USE_HASH_SET
                boost::unordered_set<int> testContainer;
            #else
                std::set<int> testContainer;
            #endif
        #endif

        StartCounter();

        for(int iTestTime = 0; iTestTime< TEST_TIME_NUMBER; ++iTestTime)
        {
            for(int iIterateConut = 0; iIterateConut< TEST_ITERATOR_NUMBER; ++iIterateConut)
            {
                testContainer.insert(iIterateConut);
            }

            for(int iIterateConut = 0; iIterateConut< TEST_ITERATOR_NUMBER; ++iIterateConut)
            {
                testContainer.erase(iIterateConut);
            }
        }

        //결과 출력
        cout << "set(Insert, erase) : " << GetCounter() <<endl;
    }

    return 0;
}

double GetCounter()
{
    #ifdef _USE_NVIDIA
        LARGE_INTEGER li;

        QueryPerformanceCounter(&li);

        return double(li.QuadPart - CounterStart)/pcFreq;

    #else

        endTime = ::timeGetTime();

        return double(endTime - startTime)*0.001;

    #endif
}

void StartCounter()
{

    #ifdef _USE_NVIDIA
        LARGE_INTEGER li;
        if(!QueryPerformanceCounter(&li))
            cout <<"QueryPerformance Fail;" <<endl;

        pcFreq = double(li.QuadPart)/100000.0;

        QueryPerformanceCounter(&li);

        CounterStart = li.QuadPart;
    #else
        startTime = ::timeGetTime();

    #endif

}



캐시를 비우고 해야겠지만..

저정도만 봐도 충분히 속도의 비교는 되리라고 생각한다..




일반 std::container




Unordered_Set 사용



boost::pool::details::default_mutex 사용




boost::pool::details::null_mutex 사용



vector.reserve로 할당 했을때


확실히 list와 set은 (아마 map도) fast_pool_allocator를 사용하였을때의 속도 향상이 있으나

vector는 그렇지 못하다.. ( 왜 그럴까..-_-)


null_mutex 와 default_mutex 구간에도 차이가 있다


이는 singleton_pool 이 (pool_allocator, fast_pool_allocator 도 내부적으로 singleton_pool 을 사용)

Thread-Safty을 보장하는 특성이 있기 때문이다.


따라서 default_mutex 는 Thread-Safty를 보장하지만  null_mutex  는 그렇지않아

락을 걸고 푸는 함수 부분이 빠져  null_mutex  가 빠른 성능을 낸다


하지만 싱글 스레드로 돌리지 않는 이상 안전성을 보장 할 수 없으므로

만약 Thread-Safty가 요구되지 않는 상황이라면  null_mutex  로 설정하는 것이 속도 향상에 도움이 될 것이다.





참고자료:


boost 폴더에 \boost\boost_1_47\libs\pool\test

http://www.boost.org/doc/libs/1_48_0/libs/pool/doc/html/index.html

http://www.gpgstudy.com/forum/viewtopic.php?postdays=0&postorder=asc&start=40&t=20337

http://godsfly.blog.me/130125905050

http://northwind.springnote.com/pages/625623

http://jacking75.cafe24.com/Boost/Pool/conception.htm

http://www.gpgstudy.com/forum/viewtopic.php?highlight=&postdays=0&postorder=asc&start=80&t=20337

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

xml_parser.hpp, json_parser.hpp  (0) 2014.06.23
boost::intrusive_ptr  (0) 2013.05.13
boost::dynamic_bitset  (0) 2013.03.08
boost::boost::unordered_map, unordered_set  (0) 2013.03.02
boost::bind, boost::mem_fn, boost::ref 조합  (0) 2013.03.01
반응형

http://blog.naver.com/sorkelf/40135586204



std::bitset의 동적사이즈


사이즈를 런타임시에 결정하는것이 가능하며 비트연산이 가능한 클래스이며

집합의 포함관계를 쓸때 주요한 용도로써 만들어졌다고 한다


std::bitset은 템플릿 매개변수로 비트 길이를 받지만, 

boost::dynamic_bitset은 생성자 매개변수로 비트길이를 받는다는 점이 다르다


STL에서는 bitset이나 vector<bool>, valarray<bool>등이 있으나,

std::bitset은 사이즈가 컴파일시 결정하여 값을 고정시킬수 밖에 없으며,

vector<bool>이나 valarray는 사이즈가 가변이긴 하지만

비트집합 전체에 대해서 한번에 비트연산을 실행하는 방법이 불완전하다.

(valarray는 시프트연산 불가)


또한 bitset이던 boost::dynamic_bitset이던 문자열형태로 출력하려면 

iostream계열만이 가능하다 (printf() 불가)



bitset의 멤버함수 +  is_subset_of와 is_proper_subset_of 라는 함수가 있다










#include <iostream>

#include <boost/dynamic_bitset.hpp>

using namespace std;


int main()

{

// 10비트의 bitset 2개 생성

boost::dynamic_bitset<> a(10);

boost::dynamic_bitset<> b(10);

// 0,3,5번째의 bit를 설정

// 1,3,8,9번째의 bit를 설정

a[0] = a[3] = a[5] = 1;

b[1] = b[3] = b[8] = b[9] = 1;

// 다양한 비트연산 수행

boost::dynamic_bitset<> c = a&b;

boost::dynamic_bitset<> d = a^b;

boost::dynamic_bitset<> e = a<<3;

cout <<"C : " << c << endl;

cout <<"D : " << d << endl;

cout <<"E : " << e << endl;


cout <<"-----------------" <<endl;

//Flip시키기 (반전)

cout <<"D Filp : " << d.flip() <<endl;

cout <<"-----------------" <<endl;

//재반전

d.flip();


// c가 e에 포함되어 있는가?

cout << (c.is_subset_of(e) ? "yes" : "no") << endl;

// c가 d에 포함되어 있는가?

cout << (c.is_proper_subset_of(d) ? "yes" : "no") << endl;

return 0;

}


[출처] boost::dynamic_bitset|작성자 풍풍풍


반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::intrusive_ptr  (0) 2013.05.13
boost::pool  (0) 2013.05.11
boost::boost::unordered_map, unordered_set  (0) 2013.03.02
boost::bind, boost::mem_fn, boost::ref 조합  (0) 2013.03.01
boost::bind & ref, cref  (0) 2013.02.28
반응형

BLOG main image





..... 


#include <boost/unordered/unordered_map.hpp >


typedef boost::unordered_map<int, std::list<int> > hashListObjectBase_sjh;




int main()

{


hashListObjectBase_sjh con;

con[0].push_back(3);


  //아래와 같이 컨테이너타입을 알아올 수 있다

hashListObjectBase_sjh::value_type::second_type::iterator begin = con[0].begin();

std::cout<<*begin<<std::endl;                        //출력결과는 3이 나온다



return 0;


}





test.cpp




unorderad_map  해쉬구조 탐색하여 값 조사





결과창















http://blog.naver.com/sorkelf/40136119399



unorderd.cpp



해쉬를 사용한 O(1)로 요소액세스 가능한 set과 map


순서에 관해서 특히 보증할수 없는 대신에
std::set이나 std::map보다도 고속으로 요소에 대해 액세스
를 할수 있는 연관 컨테이너이다.

해쉬로 구현되어 있으며
기본적으로 std::set이나 set::map과 같은방식으로 사용할 수 있다
C++표준라이브러리확장안인 TR1에도 이미 해쉬컨테이너가 들어있어
gcc4나 vc9등에서는 사용가능하나
그 이전 환경에서는 사용할수 없는 포터블한 해쉬컨테이너이다

예제





결과)









http://blog.naver.com/chriskr7/60182014718



[C++11] unordered_map performance




짬을 이용해서 이번에 사용했던 놈을 소개할 까 합니다.

std::map하고 performance면에서 차이가 많습니다.

이번에 BMT 관련해서 std::map을 이놈으로 바꾸니 find부분에서 속도가 33%정도 향상되네요.

 

단순히 테스트를 위해 읽을 파일 형성하는 소스입니다.

[-] Collapse

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <fstream>
#include <memory.h>
using namespace std;

void make_word(char* cbuf){
    int len = rand() % 6 + 1;
    cbuf[len] = 0x00;
    for(int i = 0; i <len; i++)
        cbuf[i] = 'a' + rand() % 26;
}

int main(void){
    char word[7];
    int cnt = 0;

    ofstream out("c:/test/words.txt");

    memset(word, 0x00, 7);
    srand((unsigned)time(NULL));
    while(cnt++ < 10000){
        make_word(word);
        out << word;
        memset(word, 0x00, 7);
        make_word(word);
        out << '\t' << word <<endl;
    }

    out.close();
    return 0;
}

 

실질적으로 unordered_map을 테스트 하는 소스입니다.

[-] Collapse

#include <iostream>

#ifdef __GNUC__
#include <tr1/unordered_map>
using namespace std::tr1;
#else
#include <unordered_map>
#endif

#include <map>
#include <cstdlib>
#include <string>
#include <time.h>
#include <vector>
#include <fstream>
using namespace std;

clock_t start_time, end_time;

typedef map<std::string, std::string> TIntMap;
typedef pair<std::string, std::string> TIntPair;
typedef unordered_map<std::string, std::string> TUnIntMap;

int main()
{
    TIntMap iMap;
    TUnIntMap uMap;
    TIntMap::iterator ip;
    TUnIntMap::iterator up;

    vector<std::pair<std::string, std::string>> v;

    ifstream in("c:/test/words.txt");
    if(!in)
    {
        cerr << "cannot find the file" <<endl;
        exit(EXIT_FAILURE);
    }

    string key, value;
    for(int i = 0; i <10000; i++)
    {
        in >> key >> value;
        v.push_back(std::make_pair(key, value));
    }

    // std::map Insertion
    start_time = clock();
    for(int i = 0; i < v.size(); i++){
        iMap.insert(v[i]);
    }
    end_time = clock();
    cout << "std::map insertion time elapsed : " << ((double)(end_time-start_time)/CLOCKS_PER_SEC) << endl;


    // std::unordered_map Insertion
    start_time = clock();
    for(int i = 0; i < v.size(); i++){
        uMap.insert(v[i]);
    }
    end_time = clock();
    cout << "std::unordered_map insertion time elapsed : " << ((double)(end_time-start_time)/CLOCKS_PER_SEC) << endl;


    srand((unsigned)time(NULL));
    start_time = clock();
    for(int i = 0; i < 1000000; i++)
    {
        string key = v[rand()%10000].first;
        ip = iMap.find(key);
    }
    end_time = clock();
    cout << "std::map find time elapsed : " << ((double)(end_time-start_time)/CLOCKS_PER_SEC) << endl;

    srand((unsigned)time(NULL));
    start_time = clock();
    for(int i = 0; i < 1000000; i++)
    {
        string key = v[rand()%10000].first;
        up = uMap.find(key);
    }
    end_time = clock();
    cout << "std::unorderd_map find time elapsed : " << ((double)(end_time-start_time)/CLOCKS_PER_SEC) << endl;


    in.close();

    return 0;
}

 

결과입니다. 제 PC에서 한거고요.. server에서 했을때도 속도는 거의 2.5~4배 차이가 납니다.


 



반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::pool  (0) 2013.05.11
boost::dynamic_bitset  (0) 2013.03.08
boost::bind, boost::mem_fn, boost::ref 조합  (0) 2013.03.01
boost::bind & ref, cref  (0) 2013.02.28
boost::circular_buffer  (0) 2013.02.26
반응형

BLOG main image




#include <boost/bind.hpp>

#include <boost/mem_fn.hpp>



class C{

public :

C(){

c=0;

}


int c;

};


class A{

public :

A()

{

a=0;

}

int a;

void show( C& ci ){

std::cout<< a++ << "\t"<< ci.c <<std::endl;

++ci.c;


}


};


int main()

{



std::vector<A> ai;

ai.resize(10);


C ci;

std::for_each(ai.begin(),ai.end(), boost::bind( boost::mem_fn( &A::show )  , _1 ,boost::ref(ci) ) );

        //이부분에서 boost::ref(를 제거하면 다음 for_each 에서 0부터 출력하게된다 , ref가 없다면 for_each로 넘길대

       // 복사로 넘어가게 됨으로


std::cout<<std::endl;


std::for_each(ai.begin(),ai.end(), boost::bind( boost::mem_fn( &A::show )  , _1 ,ci ) );



return 0;


}


위 소스 그대로 했을때의 출력결과


0       0

0       1

0       2

0       3

0       4

0       5

0       6

0       7

0       8

0       9


1       10

1       11

1       12

1       13

1       14

1       15

1       16

1       17

1       18

1       19






ref를 제거했을대의 결과



0       0

0       1

0       2

0       3

0       4

0       5

0       6

0       7

0       8

0       9


1       0

1       1

1       2

1       3

1       4

1       5

1       6

1       7

1       8

1       9




반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::dynamic_bitset  (0) 2013.03.08
boost::boost::unordered_map, unordered_set  (0) 2013.03.02
boost::bind & ref, cref  (0) 2013.02.28
boost::circular_buffer  (0) 2013.02.26
boost::any  (0) 2013.02.13
반응형

2008/11/04 19:14 IT 연구실/Boost.org
Bind 는 임의의 함수 포인터나 함수에 국한되지 않고, 함수 객체도 bind 할 수 있게 해 준다. 이 함수 객체를 바인드 할 경우 operator() 의 리턴 타입을 명시적으로 bind 함수에 알려 줘야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <boost/bind.hpp>
 
struct F
{
    int operator()(int a, int b) { return a - b; }
    bool operator()(long a, long b) { return a == b; }
};
 
int main( void )
{
    F f;
 
    int x = 104;
 
    bind<int>(f, _1, _1)(x);      // f(x, x), i.e. zero
 
    return 0;
}

이 처럼 bind<Return-type>(...) 을 지정해 주어야 bind 함수는 객체를 생성 할 수 있게 된다. 여기서 유심히 봐야 할 부분은 F::operator() 에 2개의 오버로드된 함수가 있는데, 이때 바인드시 전달되는 x의 타입으로 결정 되어 진다.

일반적인 함수 오버로딩과 똑같다고 생각하면 쉽게 이해가 된다.

만약, 위의 코드가 컴파일시 문제가 된다면, 아래와 같은 방법으로 컴파일 해야 할 것이다. 왜냐하면, 컴파일 마다 템플릿 구문 해석기의 구문 해석이 다르기 때문이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <boost/bind.hpp>
 
struct F
{
    int operator()(int a, int b) { return a - b; }
    bool operator()(long a, long b) { return a == b; }
};
 
int main( void )
{
    F f;
 
    int x = 104;
 
    // 이렇게
    boost::bind(boost::type<int>(), f, _1, _1)(x);
 
 
    return 0;
}

이제 함수 객체를 bind 시키는 방법을 알아 보았다면, 여기서 한가지 더 알린다면, 그 함수 객체에 result_type 이 정의 되어 있다면, 이 반환 타입을 무시할 수 있다. 예를 들자면 less<T>() 함수 객체의 경우 내부에 result_type 이 bool 로 정의 되어 있다.

이렇게 이야기 하면 .. 햇갈리니 코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <boost/bind.hpp>
#include <iostream>
 
struct F
{
    typedef int result_type;
    int operator()(int a, int b) { return a - b; } 
};
 
int main( void )
{
    F f;
 
    int x = 104;
 
    std::cout << boost::bind(f, _1, _2)(1,2);
 
    return 0;
}

하지만, 이 result_type 이 있다고 해서 모든 컴파일러가 되는 것은 아니기 때문에, 알아 두길 바란다.


여기서 bind 가 함수 객체를 받아 들였다면, 이 함수 객체를 "복사" 해서 내부적으로 가지고 있고, 그것을 사용 하게 된다. 이 때, 이 복사 하는 비용이나, 특별히 상태를 갖어야 하는 함수 객체라면, boost::ref(x) 이나 boost::cref(x)로 전달 하는것이 좋을 것이다.

이 경우, 특별히 주의 해야 할 것은, 레퍼런스 copy가 이루어 지기 때문에, 이 사실을 필히 알고 있어야 한다.(내부적으로 상태가 변한다. 또한 임시 객체의 경우, 그 소멸시점에 대해 정확히 꾀차고 있어야 한다.)


예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <boost/bind.hpp>
#include <algorithm>
#include <assert.h>
 
struct F2
{
    int s;
 
    typedef void result_type;
    void operator()( int x ) { s += x; }
};
 
int main( void )
{
    F2 f2 = { 0 };
    int a[] = { 1, 2, 3 };
 
    std::for_each( a, a+3, boost::bind( boost::ref(f2), _1 ) );
 
    assert( f2.s == 6 );
 
    return 0;
}


총평

함수 객체의 경우, 함수의 리턴값을 정해줘야 한다는 사실과, result_type을 제공한다면, 생략될 수 있다는 것을 보boo고 boost::mem_fn 이나, stl 객체 함수를 사용 한다면, 그냥 들어 가겠다 싶다. 역시 boost. 완전 사랑해

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::boost::unordered_map, unordered_set  (0) 2013.03.02
boost::bind, boost::mem_fn, boost::ref 조합  (0) 2013.03.01
boost::circular_buffer  (0) 2013.02.26
boost::any  (0) 2013.02.13
boost::variant  (0) 2013.02.13
반응형

http://goo.gl/9EFSf










Introductory Example

A brief example using the circular_buffer:

#include <boost/circular_buffer.hpp> int main(int /*argc*/, char* /*argv*/[]) { // 3개 int용량으로 환원버퍼를 만든다

boost::circular_buffer<int> cb(3); // 버퍼안에 몇개의 요소를 삽입한다. cb.push_back(1); cb.push_back(2); cb.push_back(3); int a = cb[0]; // a == 1 int b = cb[1]; // b == 2 int c = cb[2]; // c == 3 // 버퍼는 지금 가득찬다, 뒤이은 요소들을 넣는것은 가장 앞의 요소를 덮어쓸 것이다

// (역자 : push_back을 해보면 알 수 있는데 값 뿐만이 아니라 begin 이 가르키는

//        곳 또한 다음 요소를 가르키게된다, 꽉찬 상태에서 덮어쓰면 첫번째 요소는 

     //      새로운 값으로 덮어씌워지고 그것이 마지막 요소가 됨으로 ) cb.push_back(4); // 1을 4로 덮어쓴다. cb.push_back(5); // 2를 5로 덮어쓴다 // 이제 버퍼는 3,4,그리고 5를 담는다 a = cb[0]; // a == 3 b = cb[1]; // b == 4 c = cb[2]; // c == 5

// 요소들은 다른 front또는 back으로부터 pop 되어진다.

// (역자 : pop_back, pop_front는 컨테이너의 사이즈도 같이 줄게된다 ) cb.pop_back(); // 5가 지워진다. cb.pop_front(); // 3이 지워진다.


int d = cb[0]; // d == 4 return 0; }

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::bind, boost::mem_fn, boost::ref 조합  (0) 2013.03.01
boost::bind & ref, cref  (0) 2013.02.28
boost::any  (0) 2013.02.13
boost::variant  (0) 2013.02.13
Boost::foreach  (0) 2013.01.29
반응형



http://nerv2000.tistory.com/77



어떤 자료형이든 다 넣을수 있는 그런 컨테이너 사용법은 아래와 같다...



#include <boost/any.hpp>
 
int main()
{
    boost::any all;
     
    // 아래와 같이 넣으면 int형으로 변경
    // 값만 써도 알아서 인식하지만 확실하게 어떤 자료형이 들어갔는지 알기 위해
    all = (int)100;
     
    // 이상태에서는 자료형은 안바뀌고 값만 갱신
    all = 200;
 
    // 여기서 다른 자료형으로 데이터를 넣으면 자료형도 변경 되면서 데이터 갱신
    all = (float)1.3f;
 
    // 값을 꺼내는 방법 첫번째 -  타입을 비교 하고 맞을때 값 꺼내기
    if( all.type() == typeid(float) )
    {
        float &output = boost::any_cast<float &>(all);
    }
 
    // 값을 꺼내는 방법 두번째 -  try catch 문을 사용 해서 꺼내기
    // 여기서는 실패에서 에러 나겠죵...
    try
    {
        int &otput = boost::any_cast<int &>(all);
    }
    catch(const boost::bad_any_cast &e)
    {
        printf("%s\n", e.what() );
    }
     
    // 변수 초기화는 요렇게???
    all = boost::any();
 
    if( all.empty() )
    {
        printf("아무것도 없네요\n");
    }
     
    return 0;
}





http://jacking.tistory.com/701


boost::any

 

abstract

필요한 헤더

<boost/any.hpp>

가능한 일

거의 어떤한 형(型 )이라도 저장 가능한 동적형 변수

레퍼런스

en / jp

 

sample

#include <iostream>

#include <boost/any.hpp>

using namespace std;

 

struct Point

{

        Point(int ix=0,int iy=0) : x(ix), y(iy) {}

        int x, y;

};

 

static char* hw = "hello world.";

 

int main()

{

        boost::any a, b;

        a = 100; // 정수를 넣는다.

        b = hw;  // 문자열을 넣는다.

        a = b;   // any동사의 대입

        b = Point(10,20); // 사용자 정의 형도 넣어보자..

 

        // 값을 빼낸다.

        cout << boost::any_cast<Point>(b).x << endl;

        if( a.type() == typeid(int) )

               cout << "int입니다." << endl;

        else if( a.type() == typeid(char*) )

               cout << "문자열입니다." << endl;

 

        return 0;

}

출력

10.

문자열입니다.


any_cast 는 실패하면  bad_any_cast  던진다.

 

etc

생성자랑 대입 연산자가 template로 되어 있어서 넘겨진 오브젝트의 형에 따라서 대응하는 holder 클래스를 만들어 그것을 기저 클래스의 포인터에 의해서 any 중에 보관한다 라는 것으로 구현 되어 있다.



반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::bind & ref, cref  (0) 2013.02.28
boost::circular_buffer  (0) 2013.02.26
boost::variant  (0) 2013.02.13
Boost::foreach  (0) 2013.01.29
boost::random  (0) 2013.01.29
반응형

http://blog.naver.com/sorkelf?Redirect=Log&logNo=40135048244



C++에 Union같이 복수의 형태의 변수를 같은 영역에 넣는 것




Union과의 차이는 생성자의 필요한 객체도 저장이 가능하다는 것.

(Union에서는 예를들면 std::string은 쓸 수 없음)


또한 which()멤버함수를 써서 내부에 무엇이 들어있는지 알수 있다는 것


boost::any도 비슷한 역할을 한다.


Variant는 실체 형태가 실행시에 동적으로 변화는 일종의 다양한 형태도 생각할수 있기 

때문에 Visitor패턴을 구현할 때 상당히 편리하다.




#include <iostream>
#include <string>
#include <boost/variant.hpp>
using namespace std;

// 「2배 하는 」Visitor
struct do_double : boost::static_visitor<void>
{
template<typename T>
  void operator()( T& t ) const { t = t + t; }
};

int main()
{
boost::variant<int,double,string> v;
v = -2;

//이 값이 int 인지 확인
assert( v.which() == 0 );          
//int를 꺼낸다
cout << boost::get<int>(v) << endl; 
v = 3.14;
//이 값이 double인지 확인
assert( v.which() == 1 ); 
//표시만 할거라면 get<..>은 필요없음
cout << v << endl;        
v = "VANICA";
//값이 string인지 확인
assert( v.which() == 2 );        
//Visitor를 던진다
boost::apply_visitor( do_double(), v ); 
cout << v << endl;
return 0;
}




예제)









결과 






위의 예에서는 int와 double,string중에 하나가 들어있는 변수 v를 사용하고 있다


특수한 기법이 필요하긴 하지만 재귀적인 variant도 쓸 수 있다



아래에 예는 리프노드가 int로 되어있는 이진트리를 정의하고 있다.

typedef make_recursive_variant<
  int, pair<recursive_variant_, recursive_variant_>
>::type binary_tree;

// binary_tree ≒ variant<,int,pair<binary_tree,binary_tree>>




반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::circular_buffer  (0) 2013.02.26
boost::any  (0) 2013.02.13
Boost::foreach  (0) 2013.01.29
boost::random  (0) 2013.01.29
Boost::mpl  (0) 2012.12.25
반응형

http://tingcobell.tistory.com/296


Boost 목록
 

링크 : http://tingcobell.tistory.com/295




Boost.foreach 이용한 예제

#include <string>
#include <iostream>
#include <boost/foreach.hpp>
int main()
{
 std::string hello( "Hello, world!" );
 BOOST_FOREACH( char ch, hello )
 {
  std::cout << ch;
 }
 return 0;
}

std::for_each의 라이브러리를 BOOST_FOREACH 라는 매크로를 이용하여 만들어 놓여있습니다. 
이것은 주로 string 계열의 문자를 char 배열의 문자로 하나씩 복사 string의 '\0'의 문자열까지 반복적인 iterator 방식을 취하여 복사하는 형식을 취하고 있습니다.

Boost foreach에서 제공하고 있는 타입은 (Supported Sequence Types )

  • STL containers
  • arrays
  • Null-terminated strings( char and wchar_t )
  • std::pair of iterator

일반적으로 STL containers을 제공하고 있습니다. 





#include <string>
#include <iostream>
#include <list>
#include <boost/foreach.hpp>
int main()
{
 //std::string hello( "Hello, world!" );
 std::list<int> list_int;
 list_int.push_back(1);
 list_int.push_back(2);
 list_int.push_back(3);
 list_int.push_back(4);
 list_int.push_back(5);
 list_int.push_back(6);
 list_int.push_back(7);
 list_int.push_back(8);
 BOOST_FOREACH( int ch, list_int )
 {
  std::cout << ch;
 }
 
 list_int.clear();
 return 0;
}

조금 전에 위에서 언급했듯이 standard c++에서 제공하고 있는 <list>을 이용하여 BOOST_FOREACH에서 어떻게 반응하는지 보여주고 있는 예제 입니다.


자 이해가 참 쉬죠잉~*



여기서 보셔야 할 부분은 short 에서 int 로 형변환에 대해서 다루고 있습니다.

 short array_short[] = {1,2,3};
 BOOST_FOREACH( int i, array_short )
 {
  // The short was implicitly converted to an int
  std::cout << i << std::endl;
 }



deque iterator 에 관련되서 iterator 지원하는지 여부를 검사하였습니다.


 std::deque<int> deque_int;//( /*...*/ );
 deque_int.push_back(1);
 deque_int.push_back(2);
 deque_int.push_back(3);
 int i = 0;
 BOOST_FOREACH( i, deque_int )
 {
  std::cout << " cout i : " << i << std::endl;
  if( i == 0 ) 
  {
   std::cout << "i == 0 " << std::endl;
   return -1;
  }
  if( i == 1 ) 
  {
   std::cout << "i == 1" << std::endl;
   continue;
  }
  if( i == 2 ) 
  {
   std::cout << "i == 2" << std::endl;
   break;
  }
 }
 deque_int.clear();

문제 없이 동작하는 코드입니다. 어차치 테스트용도 이기 때문에 사용 문법에 대해서만 이해를 하고 어디에 쓰면

좋을지 곰곰히 생각해보셔도 될것 같습니다.  

만약에 상당히 큰 container가 존재가 하면 어떠한 iterator.begin() 부터 end()까지 순차적으로 full 스캔 한다고

생각을 해보죠. 그렇다고 한다면 문법자체도 쉽고 사용법도 용이하기 때문에 만약 속도적인 측면에서 더 낳은

역량을 가진다면 어떻게 할까요? 

당신의 선택은 어떻게 처리 하시겠습니까?

포스팅 하다가 갑자기 궁금해지기 시작하네요. 

* 속도 비교. iterator 와 관련하여 데이터가 1만? 또는 2만? 3만 10만 20만 30만 40만 60만 100만? 
* 얼마 되지 않는 데이터 비교? 1만 이하?

테스트 결과








ㅇ Iterator::vector 테스트 결과



ㅇ Boost을 이용한 BOOST_FOREACH 결과

ㅇ 테스트에 사용한 source


//BOOST_FOREACH

#include <apr-1/apr_time.h>
#include <iostream>
#include <vector>
#include <boost/foreach.hpp>

int main()
{

        std::vector<int> testVector;



        for( int i = 0; i < 1000000 ; i++ )
        {
                testVector.push_back( i );
        }

        apr_time_t startTime = apr_time_now();
        std::cout << "Data Count : " << testVector.size() << std::endl;
/*
        for( std::vector<int>::iterator iter = testVector.begin(); iter != testVector.end(); iter++)
        {
                //std::cout << *iter << std::endl;
        }
*/
        BOOST_FOREACH( int i, testVector )
        {
                //std::cout << i << std::endl;
        }
        apr_time_t endTime = apr_time_now();

        apr_time_t resultTime = endTime - startTime;
        std::cout << "result Time : " << resultTime << std::endl;


        testVector.clear();

        return 0;
}


//iterator vector 을 이용한 테스트 소스
#include <apr-1/apr_time.h>
#include <iostream>
#include <vector>
#include <boost/foreach.hpp>

int main()
{

        std::vector<int> testVector;



        for( int i = 0; i < 1000000 ; i++ )
        {
                testVector.push_back( i );
        }

        apr_time_t startTime = apr_time_now();
        std::cout << "Data Count : " << testVector.size() << std::endl;

        for( std::vector<int>::iterator iter = testVector.begin(); iter != testVector.end(); iter++)
        {
                //std::cout << *iter << std::endl;
        }
/*
        BOOST_FOREACH( int i, testVector )
        {
                //std::cout << i << std::endl;
        }
*/ 
        apr_time_t endTime = apr_time_now();

        apr_time_t resultTime = endTime - startTime;
        std::cout << "result Time : " << resultTime << std::endl;


        testVector.clear();

        return 0;
}

리눅스에서 apr 라이브러리를 이용하여 시간을 측정하였습니다.

네 전 윈도우 잘 모릅니다..-0-;;;; 대략 시간 구하는거 알고 있지만, 편리한 걸 선택했습니다.


ㅇ 결론 
BOOST라고 하면 단순하게 안정화된 라이브러리 이기 때문에 빠를 것이라고 생각했었다. 하지만 테스트를 이용하여

사용해 본 결과 빠르지 않다는 결론을 얻었다. 지금의 테스트를 본다면 단순 무리수가 많은 테스트 일 수 있다. 

왜냐면 BOOST에 적용되어 있는 BOOST_FOREACH 매크로의 경우 내부 하단에서 처리 하는 시간이 많이 걸릴 수

있는 부분이기에 생각해 볼 필요성은 있다. 하지만 단순 테스트의 경우 BOOST_FOREACH 매크로 사용보다는 순수

iterator가 좋다는 결론을 얻을 수 있다.





   

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::any  (0) 2013.02.13
boost::variant  (0) 2013.02.13
boost::random  (0) 2013.01.29
Boost::mpl  (0) 2012.12.25
boost::thread  (0) 2012.12.25
반응형


 

http://www.boost.org/doc/libs/1_51_0/doc/html/boost_random.html

boost 에서 랜덤 생성도 제공해 줍니다 rand(time(0)) 을 쓸때 생기는 흔한 (혹은 뻔한) 패턴을 피해서 각자 만들곤

하는데 그런 노고를 안해도 될 듯 하네요

 

1~6 랜덤 숫자 구하기

1
2
3
4
5
6
7
8
9
#include <boost/random.hpp>
 
int GetDice()
{
    boost::random::mt19937 rng;
    boost::random::uniform_int_distribution<> six(1,6);
 
    return six(rng);
}

 

특정 숫자 범위내에서 구하기

1
2
3
4
5
6
7
8
9
10
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
 
int GetRand()
{
    boost::random::mt19937 gen;
    boost::random::uniform_int_distribution<> dist(1, 6);
     
    return dist(gen);
}

 

랜덤 패스워드 구하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <boost/random/random_device.hpp>
#include <boost/random/uniform_int_distribution.hpp>
 
void Password()
{
    std::string chars(
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "1234567890"
        "!@#$%^&*()"
        "`~-_=+[{]{\\|;:'\",<.>/? ");
 
    boost::random::random_device rng;
    boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
     
    for(int i = 0; i < 8; ++i)
        std::cout << chars[index_dist(rng)];
 
    std::cout << std::endl;
}











boost random  tech-note 

2006/09/07 17:08

복사http://blog.naver.com/moonday/60028409808


1 링크 및 설명 #

2 개요 #

이 라이브러리는 몇가지 종류의 의사난수 생성기들을 제공합니다. 의사 난수 생성기의 품질은 알고리즘과 매개변수에 따라 확연히 차이가 나는 특징이 있습니다. 이 라이브러리는 이러한 알고리즘들을 boost::random에 숨겨둔 템플릿 매개변수를 사용한 클래스 템플릿으로 구현하고 있습니다. 모든 특정 매개변수 선택사항들은 boost namespace내에 typedef 형태로 알맞게 지정되어있습니다

의사 난수 생성기는 프로그램 실행중에는 그렇게 자주 구성(초기화)되지 않는 경향이 있는데, 이는 다음과 같은 이유 때문입니다.

첫째, 생성기의 초기화는 생성기 내부 정보의 전반적인 초기화를 요구합니다. 따라서, 많은 내부 상태를 가지고 있는 생성기는 초기화 비용이 많이 듭니다.(아래 참조)

둘째, 초기화는 언제나 생성될 난수배열의 "씨앗(seed)"값으로 사용될 값을 필요로 합니다. 예를 들어, seed 값을 얻는 방법들 중 하나는 가능한한 높은 해상도의 현재시간(예를 들면, 마이크로초 또는 나노초)를 적용하는 것입니다. 이때 현재시간을 기준으로 seed값을 지정하여 의사난수생성기가 다시 초기화 될 때에는 이전에 처음 초기화될 때 사용되었던 seed값의 시간으로부터 거의 상수에 가까운(난수성향이 아닌) 값을 취하게 됩니다. 설상가상으로 시스템 클럭수가 현저히 낮은 경우 이 차이는 거의 0에 가깝게 되며, 결과적으로 생성기는 같은 순서의 난수 배열을 생성하게 됩니다. 몇몇 경우에 있어서 이는 원하는 결과가 아닐 겁니다.

아래에 설명한 모든 의사 난수 생성기는 CopyConstructible 및 Assignable로부터 상속되었다는 점을 알아두시기 바랍니다. 생성기를 복사하거나 대입하는 것은 내부 상태 모두를 복사한다는 것을 의미하므로, 원본과 복사본 모두 같은 순서의 난수 배열을 생성하게 될 것입니다. 종종 이러한 특징을 원하지 않을 경우도 있습니다. 특히, std::generate와 같은 표준 라이브러리를 채용한 알고리즘에 주의하십시요. 이들은 값에 의한 참조방식의 매개변수로서 함수자(functor)를 가지며, 이는 복사생성자를 호출하는 효과가 있습니다.

다음 표는 생성기들의 몇가지 특징을 요약한 것입니다. 사이클 길이는 생성기 품질을 대략적으로 추정할 수 있는 값입니다. 대략적인 상대 속도는 성능 평가기중이며, 높을수록 더빨리 난수생성처리를 수행한다는 의미입니다.

생성기사이클 길이대략적인 요구 메모리대략적인 상대 실행속도비고
minstd_rand2^31-2sizeof(int32_t)40-
rand482^48-1sizeof(uint64_t)80-
lrand48 (C 라이브러리)2^48-1-20전역함수
ecuyer1988대략 2^612*sizeof(int32_t)20-
kreutzer1986?1368*sizeof(uint32_t)60-
hellekalek19952^31-1sizeof(int32_t)3몇몇 차원에서 좋은 단일 분포(uniform distribution)를 가짐
mt11213b2^11213-1352*sizeof(uint32_t)100350 차원에서 좋은 단일 분포(uniform distribution)를 가짐
mt199372^19937-1625*sizeof(uint32_t)100623 차원에서 좋은 단일 분포(uniform distribution)를 가짐
lagged_fibonacci607대략 2^32000607*sizeof(double)150-
lagged_fibonacci1279대략 2^670001279*sizeof(double)150-
lagged_fibonacci2281대략 2^1200002281*sizeof(double)150-
lagged_fibonacci3217대략 2^1700003217*sizeof(double)150-
lagged_fibonacci4423대략 2^2300004423*sizeof(double)150-
lagged_fibonacci9689대략 2^5100009689*sizeof(double)150-
lagged_fibonacci19937대략 2^105000019937*sizeof(double)150-
lagged_fibonacci23209대략 2^120000023209*sizeof(double)140-
lagged_fibonacci44497대략 2^230000044497*sizeof(double)60-

표를 살펴보면, 난수 생성기를 선택함에 있어서 품질, 성능, 메모리에 관한 trade-off가 존재한다는 것을 알 수 있습니다. The multitude of generators provided in this library allows the application programmer to optimize the trade-off with regard to his application domain. Additionally, employing several fundamentally different random number generators for a given application of Monte Carlo simulation will improve the confidence in the results.

If the names of the generators don't ring any bell and you have no idea which generator to use, it is reasonable to employ mt19937 for a start: It is fast and has acceptable quality.

Note: These random number generators are not intended for use in applications where non-deterministic random numbers are required. See nondet_random.html for a choice of (hopefully) non-deterministic random number generators.

In this description, I have refrained from documenting those members in detail which are already defined in the concept documentation.
 
 


반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::variant  (0) 2013.02.13
Boost::foreach  (0) 2013.01.29
Boost::mpl  (0) 2012.12.25
boost::thread  (0) 2012.12.25
boost::weak_ptr  (0) 2012.11.24
반응형

BLOG main image



아래 포스트는 http://cafe.naver.com/ecpp 에서 부분을 조금씩 발췌한 글입니다 (보기 편하게 색깔등만 편집되었습니다)









boost::mpl 이 할줄 아는 것이라고는 결국엔 컴파일 시점에 '타입 추론' 과 '상수값 추론' 밖에 없습니다.





일단 간단한 예제를 한번 보겠습니다.


ex1)


#include <boost/mpl/aux_/test.hpp>

 

MPL_TEST_CASE()
{
       MPL_ASSERT(( boost::is_same<char, char> ));
       //MPL_ASSERT(( boost::is_same<int, char> ));
}



실행시 별로 어려움은 없으리라 생각됩니다.

 

  • 일단, vc7.1 ( 2003 버전 ) 서는 위의 코드를 컴파일하게되면 에러가 발생할 수 있습니다.

    MPL_ASSERT 의 내부구현에서 컴파일에러를 발생하는 데 그 원인은 정확하게 짚어보지는 않았습니다.

    매크로를 처리하는데 있어서 vc7.1 이 버그가 있다고만 추측만 할 뿐입니다.

    컴파일을 성공시키기 위해서는 Project Setting - C/C++ - 일반 - 디버깅정보형식 을 ZI 말고 Zi 로 바꿔주시면 컴파일시에 컴파일러는

    아무런 불평을 하지 않습니다. 물론 2005 버전에서는 아무런 문제가 없습니다.



MPL_ASSERT 는 BOOST_MPL_ASSERT 를 재정의한 것일 뿐입니다. AssistX 란 툴을 쓰신다면 Alt+G 키로 정의를 금방 볼수 있죠.

 

다른 것은 직접 읽어보시면 될터이지만, 쉽게 이해가 가지 않는 부분이 파라메타가 "Boolean nullary Metafunction" 이어야 한다고



 "불린 널러리 메타함수" 가 무엇일까요?




  • 메타함수( Metafunction ) 

    공개적으로 접근할 수 있는 type 이라는 이름의 내포된 결과형식을 가진,

    모든 템플릿 매개변수들이 형식인 클래스템플릿 혹은 클래스

       (써비왈 - 메타함수는 boost::mpl 에서 상당히 중요한 개념입니다. C++ Meta Programming 에서는 메타함수는 

       boost::mpl 의 중심적인 추상이란 표현을 하였는데요. 대략 의미는 boost::mpl 의 대부분의 것들이 type 을 내포하고, 

       그 대부분의 것들이 메타함수라는 뜻으로 표현한 듯 싶습니다.)

  • 무항 메타함수( Nullary Metafunction )

    템플릿 매개변수를 받지않는 메타함수

    (써비왈 - 템플릿클래스가 아니고 일반 클래스라면 무항메타함수이겠죠? 또 전체특수화가 된 클래스템플릿이라면 역시 무항메타함수입니다.)

  • 수치메타함수( Numerical Metafunction )

    수치값을 감싸는 래퍼형식을 돌려주는 메타함수, 편의상 많은 수치 메타함수들은 내포된 ::value 멤버를 직접 제공한다.

    그런 메타함수들의 다음과 같은 좀 더 일반적읜 표현을 사용하는 대신,

    some_numerical_metafunction<Arg>::type::value  다음처럼 수치결과에 직접 접근할 수 있다.

    some_numerical_metafunction<Arg>::value


위의 정의된 내용들은 C++ Meta Programming 에서 발췌한 것입니다. 좀 더 구체적으로 접근을 해볼까요?

 


ex1)


#include <boost/mpl/aux_/test.hpp>

 

MPL_TEST_CASE()
{
       MPL_ASSERT(( boost::is_same<char, char> ));
       //MPL_ASSERT(( boost::is_same<int, char> ));
}


위의 ex1 에서 is_same 은 Boolean Nullary Metafunction 인가요? 왠지 Nullary 같지는 않죠?


is_same 의 정의를 보면 type 이라는 멤버가 있습니다. 메타함수인것은 확실히 맞습니다. 그렇지만 Nullary 는 아닙니다.


is_same::type 이 Boolean Nullary Metafunction 입니다. 즉 is_same 이 리턴해주는(::type) 타입이 


Boolean Nullary Metafunction 이라는 것으로 보셔야 합니다.






BOOST_MPL_ASSERT 는 boolean nullary metafunction 을 인수로 받게 됩니다.


  • boolean - ::value 는 true or false 여야 한다.

    nullary - 템플릿인수는 특화되었거나 없어야 한다.

    metafunction - ::type 이 존재해야한다.



   

즉 아래와 같은 구현도 boolean nullary metafucntion 이 될 수 있습니다.

 

struct Boolean_nullary_Metafunction_true
{
     typedef Boolean_nullary_Metafunction_true type;
     static const bool value = true;
};


struct Boolean_nullary_Metafunction_false
{
    typedef Boolean_nullary_Metafunction_false type;
    static const bool value = false;
};

 

BOOST_MPL_ASSERT(( Boolean_nullary_Metafunction_true )); // 컴파일 에러 없음.












#include <boost/mpl/assert.hpp>              // BOOST_MPL_ASSERT 땜에 필요하죠.

#include <boost/mpl/int.hpp>                   // boost::mpl::int_ 를 정의하고 있는 파일입니다.

#include <boost/type_traits/is_same.hpp>  // type_traits 란 영역에 존재한다고 강조했었습니다.



namespace mpl = boost::mpl;                    // boost::mpl 은 좀 길죠?



 

void main()

{

       // 1. 컴파일에서 아무 문제가 없습니다.

      BOOST_MPL_ASSERT(( boost::is_same< bool, bool > ));

 

      // 2. 컴파일에서 에러로그가 발생하죠? 컴파일에러로그로 정보를 출력해줍니다.

      BOOST_MPL_ASSERT(( boost::is_same< bool, int > ));     

      

      // 3. 인수로 타입을 넣어야 하는데 값을 넘겨주죠? 사용법자체가 잘못되었죠. 엄청난 에러메세지들이 뜰겁니다.

      BOOST_MPL_ASSERT(( boost::is_same< 2, 2 > ));

 

      // 4. 이것은요? 클래스타입을 넘겼기 때문에 아무런 문제가 없습니다.

      BOOST_MPL_ASSERT(( boost::is_same< mpl::int_<2>, mpl::int_<2> > ));

 

      // 5. 이것은 2.와 같이 is_same<> 에서 넘겨준 두개의 타입이 다르다는 의미로 컴파일에러가 납니다.

      BOOST_MPL_ASSERT(( boost::is_same< mpl::int_<2>, mpl::int_<3> > ));

}




 

boost::mpl::int_ 는 한번도 본적이 없었는데요. boost::mpl::bool_ 과 거의 같은 구조로 정의되어있다고 보시면 됩니다.

int 란 성격상 추가된 함수가 존재하는데 prior, next 가 존재합니다. 실행시점의 연산자 ++, -- 정도로 보시면 됩니다.





 







반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

Boost::foreach  (0) 2013.01.29
boost::random  (0) 2013.01.29
boost::thread  (0) 2012.12.25
boost::weak_ptr  (0) 2012.11.24
boost::shared_ptr  (0) 2012.11.18
반응형

BLOG main image





boost 페이지


http://www.boost.org/doc/libs/1_36_0/doc/html/thread/thread_management.html#thread.thread_management.thread.multiple_argument_constructor


를 보면 다음 구문으로 join에 멤버함수에 대한 역할을 알 수 있다




In order to wait for a thread of execution to finish, the join() or timed_join() member functions of the boost::thread object must be used.



번역하기 귀찮은 사람들을 위해 써놓자면


끝내기위한 쓰래드실행을 기다리기위해서, join()  또는 timed_join()   boost::thread 오브젝트의 멤버함수들이 사용되어져야한다.


임을 알 수 있다 ∴  .join() 함수 - 쓰레드가 종료될 때까지 대기하게된다



p.s waitForSingleObject 쯤으로 생각해 두면 될듯, 아래 포스트들은 역시 Boost::thread에 관한 실행 예제들과 좀 더 자세한 멤버들에 대한 내용이다




[condition 과 mutex 의 사용시 주의사항]



        //condition 을 사용하기전에 주의해야하는 점이 아래 나온다

//A condition object is always used in conjunction with a mutex object(an object whose type is a model of a Mutex or one of its refinements). 

//The mutex object must be locked prior to waiting on the condition, which is verified by passing a lock object

        //http://www.boost.org/doc/libs/1_34_0/doc/html/boost/condition.html 에서 발췌

 

      condition 을 사용하기전에 반드시 mutex를 lock 건것에 대한 변수로 wait 해야 된다는것.

     다시말해 condition 은 뮤텍스를 lock 한 객체를 받아야야하고 이것

     _condition.wait(lock); 로 대기상태로 두고, // lock 은 뮤텍스를 락한것

     다른 스레드에서 _condition.notify_one(); or _condition.notify_all(); 로 wait 하고 있는 lock 을 깨울 수 있다

     

      


boost::mutex::scoped_lock lock(_mutex);

while(true){

_condition.wait(lock); //checkThread 함수 자체가 멈춘다

runThread();

}









http://www.boost.org/doc/libs/1_41_0/doc/html/thread/thread_management.html#thread.thread_management.threadgroup

Joining and detaching

When the boost::thread object that represents a thread of execution is destroyed the thread becomes detached. Once a thread is detached, it will continue executing until the invocation of the function or callable object supplied on construction has completed, or the program is terminated. A thread can also be detached by explicitly invokingthe detach() member function on the boost::thread object. In this case, the boost::thread object ceases to represent the now-detached thread, and instead representsNot-a-Thread.

In order to wait for a thread of execution to finish, the join() or timed_join() member functions of the boost::thread object must be used. join() will block the calling thread until the thread represented by the boost::thread object has completed. If the thread of execution represented by the boost::thread object has already completed, or the boost::thread object represents Not-a-Thread, then join() returns immediately. timed_join() is similar, except that a call to timed_join() will also return if the thread being waited for does not complete when the specified time has elapsed.



쓰래드가 





http://mytechdic.blogspot.kr/2010/03/boostthread-%EC%9D%98-sleep-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0.html


boost 라이브러리의 thread를 사용할 때 sleep을 사용할 일이 자주 생기는데

boost::thread::sleep 함수는 사용하기가 좀 번거롭습니다.

대신 boost::this_thread::sleep 함수를 사용하면 됩니다.

 

[code cpp]boost::this_thread::sleep(boost::posix_time::milliseconds(30));[/code]

 

인자로 사용되는 boost::posix_time::milliseconds 대신boost::posix_time::seconds 함수 등으로 시간 단위를 지정할 수 있습니다.






http://jeremyko.blogspot.kr/2012/03/boost-thread-13.html


boost::thread

OS간 포터블한 쓰레드 처리를 위해서 유용하다.
사용법은 다음과 같다. boost::thread 생성자에 쓰레드로 동작할 함수를 전달하면,
생성즉시 thread()가 동작한다.


#include <boost/thread.hpp>
#include <iostream>

void wait(int seconds)
{
   boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

void thread()
{
   for (int i = 0; i < 5; ++i)
   {
         wait(1);
         std::cout << i << std::endl;
   }
}

int main()
{
   boost::thread t(thread);
   t.join(); //thread()가 종료할때까지 blocking된다.
}

t변수를 이용해서 생성된 쓰레드에 접근할수 있다. 그런데, t변수가 스코프를
벗어나서 삭제되더라도 쓰레드 함수는 계속 동작한다.
쓰레드는 언제나 boost::thread 타입의 변수에 바인드되지만, 한번 생성되고 난 이후에는
그 변수에 의존적이지 않다. detach() 함수를 이용하면 이러한 boost::thread 타입
변수도 불필요하다.

위의 예제가 쓰레드종료를 기다리는 경우라면, 다음은 인터럽트되는 경우를 보여준다.

#include <boost/thread.hpp>
#include <iostream>

void wait(int seconds)
{
   boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

void thread()
{
   try
   {
         for (int i = 0; i < 5; ++i)
         {
       wait(1);
      
       std::cout <<"thread:"<< boost::this_thread::get_id()<<" "<< i << std::endl;
         }
   }
   catch (boost::thread_interrupted&)
   {
   std::cout << "thread interrupted" << std::endl;
   }
}

int main()
{
std::cout << boost::thread::hardware_concurrency() << std::endl; //동시에 실행가능한 쓰레드 갯수
    std::cout <<"(main)thread main id:" << boost::this_thread::get_id()<< std::endl;    
   boost::thread t(thread);
    std::cout <<"(main)thread id:" << t.get_id()<< std::endl;   
   wait(3);
   t.interrupt();
   t.join();
}

출력:
(main)thread main id:001696A8
(main)thread id:00169C70
thread:00169C70 0
thread:00169C70 1
thread:00169C70 2
thread interrupted

스레드 객체에 대해서 interrupt()를 호출하면, 그 쓰레드는 인터럽트된다.
이것은 해당 쓰레드에서 boost::thread_interrupted 예외를 발생 시키게 한다.
중요한점은, 이것은 쓰레드가 interruption point에 도달해야지만 발생된다는 것이다.
만약 쓰레드가 interruption point를 가지고 있지 않다면, interrupt()를 호출해도
아무것도 발생되지 않는다. 쓰레드는 interruption point에 도착할때마다,
interrupt()가 호출되었는지를 확인할것이고, 호출된경우 boost::thread_interrupted
예외가 전달될것이다.
Boost thread는 다음과 같은 interruption point를 정의하고 있다.

boost::thread::join()
boost::thread::timed_join()
boost::condition_variable::wait()
boost::condition_variable::timed_wait()
boost::condition_variable_any::wait()
boost::condition_variable_any::timed_wait()
boost::thread::sleep()
boost::this_thread::sleep()
boost::this_thread::interruption_point()

위의 예에서 sleep()은 5번 호출되고 있는데,
이경우에만 interrupt()호출 여부를 확인할것이고, 그외 시간에는 쓰레드는 인터럽트 되지 않는다.

boost::this_thread::disable_interruption
boost::this_thread::restore_interruption
쓰레드내에서 임시 객체를 선언하면 인터럽트되는것을 조정할수 있다.

void g()
{
    // interruption enabled here
    {
        boost::this_thread::disable_interruption di;
        // interruption disabled
        {
            boost::this_thread::restore_interruption ri(di);
            // interruption now enabled
        } // ri destroyed, interruption disable again
    } // di destroyed, interruption state restored
    // interruption now enabled
}


쓰레드 생성시, 함수에 입력인자 전달
void thread_func   (int i,double d,std::string s)
{
    std::cout << i<<":"<<d<<":"<<s<< std::endl;
}

int main()
{
    boost::thread t(thread_func, 42,3.141,"hello world");
    t.join();
}

인자는 모두 복사되어져서 전달되므로 , 참조자를 넘기는 경우는
boost::ref()를 이용한다.

int i;
void thread_func(int& j);
boost::thread t (thread_func,boost::ref(i));

Movable 
boost::thread 인스턴스간에는 소유권 이전이 가능하다.

#include <boost/thread.hpp>
#include <iostream>

void some_function()
{
    std::cout << "some_function..."<< std::endl;
}

boost::thread create_thread()
{    
    boost::thread t(some_function);

    return boost::move(t);
}

boost::thread threads[45];

int main()
{
    threads[12] = boost::move( create_thread() );
    threads[12].join();
}








http://cafe.naver.com/totalprogramming/14  에서 일부 발췌




쓰레드 함수에 파라메터를 넘겨줘야 하면 -> boost::bind를 쓰자

클래스 멤버 함수를 쓰레드로 돌릴 경우에도, bind를 써야 하고,

전역에 있는 함수를 쓰레드로 돌릴 경우는 bind를 사용하지 않아도 된다.

전역 변수이고 클래스 함수이고의 구분은 컴파일러가~알아서~한다




 



가변 인수를 받아들이는 thread함수. 생성자일 경우

Thread Constructor with arguments


void CKsc::start()

{

    thread_ = new boost::thread( boost::bind(&CKsc::f, this, 1, 2, this ));

}

생성과 동시에 thread 함수인 f가 돌기 시작한다.

두번째 매개 변수는 첫번째로 넘긴 CKsc::f의 대상 객체가 된다. 위의 예제에서는 CKsc객체 내에서 호출을 하기 때문에

this가 가능한것이다. 외부에서 할 경우에는

CKsc a;

    boost::thread* thread_ = new boost::thread( boost::bind(&CKsc::f, a, 1, 2, this ));

혹은

   boost::thread* thread_ = new boost::thread( boost::bind(&CKsc::f, &a, 1, 2, this ));

 

boost는 쓰레드 함수 지정시 이미 쓰레드는 자동으로 수행된다는 점이다

 

이렇게 하면 된다.

첫번째 처럼 하면 a가 복사되어 넘어가게 되는것이고, 두번째 예제처럼 하면 포인터가 넘어가서 공유가 된다.

 

 

void hello(const char* s)
...
int main() {
    thread t( bind(&hello, ",world") );

}




인수 없는 thread 함수를 받아들일 경우 생성자.

Thread Constructor


boost::thread ta(&show_trace);

ta.join();











http://cafe.naver.com/javacircle/12487



#include
 <iostream>
#include <boost/thread.hpp>
using namespace std;
using namespace boost;

void show_a() // 100만번 'a'를 출력
{
    for(int i=0; i!=1000000; ++i)
        cout << 'a';
}

void show_b() // 100만번 'b'를 출력
{
    for(int i=0; i!=1000000; ++i)
        cout << 'b';
}

int main()
{
    thread ta( &show_a ); // show_a 함수를 실행하는 스레드를 실행 
    thread tb( &show_b ); // show_b 함수를 실행하는 스레드를 실행 
    ta.join();
    tb.join(); // join() 함수로, 스레드가 종료될때까지 대기.
    return 0;
}

 

실행결과:

thread1

 

aaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbb

aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb

aaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbb

....







http://www.viper.pe.kr/cgi-bin/moin.cgi/Boost/Thread_1




1. 참고링크 [Bottom] [Top]

2. boost::thread 라이브러리 [Bottom] [Top]

<!> boost::thread 라이브러리에 대한 설명

3. <boost/thread/thread.hpp> 헤더 파일 [Bottom] [Top]

3.1. thread 클래스 [Bottom] [Top]

  • Thread 객체를 생성하는 클래스로 boost::thread 라이브러리 의 (!) 핵심 Thread 클래스.

  • 생성자
    Toggle line numbers
    thread( const boost::function0< void >& threadfunc );
    
    • 쓰레드 객체를 생성한다.
    • 생성자의 매개변수는 반환값이 void 형이고 매개변수가 없는 함수 또는 함수 객체를 전달한다. 자세한 것은 functionN<> 클래스를 참고한다.

  • 멤버 함수
    • join() 함수 - 쓰레드가 종료될 때까지 대기한다.
    • sleep( xt ) 함수 - xt 로 지정된 시간 만큼 쓰레드를 대기한다.
    • yield() 함수 - 쓰레드를 Ready 상태로 전환하고 Context Switching 한다.

3.2. thread_group 클래스 [Bottom] [Top]

  • Thread 객체를 생성하고 관리해주는 Thread Manager.

  • 멤버 함수
    • create_thread( threadfunc ) 함수 - 쓰레드를 생성한 후 쓰레드 관리 컨테이너에 추가한다.
    • add_thread( thrd ) 함수 - 생성된 쓰레드를 쓰레드 관리 컨테이너에 추가한다.
    • remove_thread( thrd ) 함수 - 지정된 쓰레드를 쓰레드 관리 컨테이너에서 삭제한다.
    • join_all() 함수 - 모든 쓰레드가 종료될 때까지 대기한다.
    • size() 함수 - 현재 쓰레드 관리 컨테이너의 크기 (쓰레드 개수) 를 구한다.











http://blog.naver.com/pronaman/60125230225



Boost.Thread는 데이터 공유의 실행 스레드를 사용 가능하게 하고, 스레드를 이동시킬 수 있으며 스레드간에 데이터를 동기화하는 함수를 제공한다. 

#include <boost/thread.hpp>

 

사용방식은 다음과 같다. 
- 스레드함수가 외부에 있을때 : boost::thread myThread( &func );
- 스레드함수가 클래스의 멤버 함수일때 : boost::thread myThread( boost::bind(&ClassName::func, this) ); 

간단한 사용법은 다음과 같다.

#include "boost/thread.hpp"
#include <iostream>
#include <time.h>

void ThFunc(void *p, int a, int b, int c, int d)
{
    const char *pszMessage = (const char *)p;
    std::cout << pszMessage << ":" << (a+b+c+d) << std::endl;
    boost::this_thread::sleep(boost::posix_time::seconds(2));          // 2초 동안 정지
}
  
int main(int argc, char **argv)
{
    static const char *pszMessage = "boost thread";
    boost::thread t(ThFunc, (void *)pszMessage, 1102420484096);  // 여러개의 인자를 쓰레드 함수에 전달 할 수 있음.
  
    t.timed_join(boost::posix_time::seconds(1));                       // 1초 동안 쓰레드 종료 대기
    t.join();                                                          // 쓰레드 종료 대기 (무한)
      
    return 0;
}

여러개의 스레드간의 임계영역 처리시 호환성때문에 윈도우의 크리티컬 섹션과 같은 클래스는 없는것 같다. 뮤텍스로 처리한다.

사용법은 다음과 같다.

 

boost::mutex mutexVar; // Lock을 걸 mutex 변수

/////////////////////////////////////////
스레드 합수 안에서 스코프를 만들어 락을 처리하는 것이 좋다.

{
     boost::mutex::scoped_lock( mutexVar ); // Mutex Lock이 걸림
}

 

스레드를 실행 후 정지시켰다가 특정 시점에 활성화 하고자 할 경우 윈도에서는 이벤트 객체를 사용했으나 boost는

condition 이란 객체를 사용한다. 컨디션은 쓰레드를 잠들게 하고 동작하게 하는 제어 변수로  사용될 수 있다.

condition.wait(mutexVar);

 

스레드에서 이와 같이 선언한 경우 스레드가 멈추게 된다. 이때 다음 함수로 활성화할 수 있다.

 

condition.notify_one(); // 잠들어있는 것중에서 경쟁적으로 한개만 깨울때
condition.notify_all(); // 잠들어있는 모든 녀석을 깨울때

[출처] thread|작성자 마니 조우성






Advanced Usage

----------------------------------------------------------------------------------
  • Thread를 제어하는 2가지: Mutex 와 condition

    • Mutex : 운영체제에서 익히나온 것이다. Thread 가 동시다발적으로 어느 특정 리소스를 사용할때, 한개의 Thread만 사용하게 하고싶을때 사용하는 녀석이다. 제대로 사용하지 않으면 성능저하를 일으키니 디자인설계때부터 조심히 사용해야 하는 녀석이다. 추천하는

      - header : #include <boost/thread/mutex.hpp>
      - 추천하는 것 : boost::mutex::scoped_lock
      - 이유 : 사용하기 편하다. 이 변수를 괄호 안에 선언하게 되면 괄호의 끝을 만날때까지 잠금이 되고, 괄호를 벗어나게되면 락이 풀린다. (이에 대한 원리는 간단히 생각해보면 되는데, 생성자에서 락을 걸고, 소멸자에서 락을 푸는 코드를 삽입한 것이다)

      boost::mutex mutexVar; // Lock을 걸 mutex 변수

      if ( test_module == true )
      {
           boost::mutex::scoped_lock( mutexVar ); // Mutex Lock이 걸림
           // Do something
      } // 이 시점에서 락이 풀린다.


    • condition : 쓰레드를 잠들게 하고 동작하게 하는 제어 변수. 보통 어떤 값을 기다릴때 while 로 돌리는 방법이나 sleep 을 줘서 일정시간마다 체크하는 경우가 있는데 이는 대부분 비효율적이며, 데이터가 아직 완성이 안되어있으면 잠들어있다가 완료시점에 신호를 보내어 깨어나게 한다. 기억해야 할 점은, 만약 집단의 쓰레드들을 관리해서 경쟁적으로 한개씩 깨어나게 하고 싶다면 하나의 condition 변수를 쓰레드들 사이에서 공유해야 한다.

      void threadFunction(void)
      {
           while( true )
           {
                boost::mutex::scoped_lock lock( mutexVar );
                // Thread 초기화 작업
                condition.wait(mutexVar); // 현재 실행중인 Thread는 대기모드로
                                                    // 들어가고 mutexVar로 걸린 락이 해지
                                                    // 된다.
      // 외부 코드에서 깨우고 싶을때.. 
      condition.notify_one(); // 잠들어있는 것중에서 경쟁적으로 한개만 깨울때
      condition.notify_all(); // 잠들어있는 모든 녀석을 깨울때






The Boost.Threads Library


http://diehard98.tistory.com/141




불과 몇년 전만 하더라도 멀티 스레드를 사용하는 프로그램은 드물었다. 오늘날의 인터넷 서버 프로그램은 다수의 클라이언트 연결을 위해 여러개의 스레드를 이용한다. 효율과 생산성을 최대화 하기 위해서 트랜잭션 서버들은 분리된 여러개의 스레드를 이용하곤 한다. GUI 프로그램 또한 오랜 시간이 걸리는 작업은 분리된 스레드를 통해 백그라운드로 작업을 하면서 동시에 사용자의 입력은 실시간을 받아들인다. 이런식으로 나열하면 수도 없이 많다. 그만큼 멀티 스레드는 보편화 되었다는 것.

기존의 C++ Standard는 멀티 스레드에 대해 언급조차 하지 않는다. 심지어는 프로그래머에게 멀티 스레드 C++ 프로그램이 작성 가능한지 조차 알려주지 않는다. (과거 C나 C++ 은 멀티 스레드 환경에서 설계 되지 않았기 때문) 물론 기본적인 함수를 이용한 멀티 스레드 프로그램이 작성 불가능 한것은 아니지만, 프로그래머는 그럼에도 불구하고 운영체제가 지원하는 스레드 관련 라이브러리를 이용해서 작성한다. 자, 이것은 두가지 문제를 가지고 있다. 우선, 이 운영체제에서 제공하는 라이브러리들은 거의 C 라이브러리들인데다가 C++에서 사용시에는 주의해야 한다. 그리고 각각의 운영체제는 자신만의 멀티 스레드 조작 함수를 사용한다는 것이다. 이렇게 만들어진 코드는 우선 'Non-Standard(비기준)' 인데다가 'Non-Portable(비호환성)' 이다. 운영체제마다 쓰는 함수가 다르니 윈도우에서 돌리던 프로그램 유닉스에서 돌리려면 코드를 다 뜯어 고쳐야 한다는 말... 고로, Boost.Therads 라는 라이브러리를 만들었다는 말이다. 이 두 문제를 한방에 해결하기 위해서...

Boost는 C++ Standards Committee Library Working Group의 멤버들이 C++의 새로운 라이브러리를 만들이 위해 시작되었다. 현재 대략 2000명이나 된다구. 수많은 boost의 라이브러리를 thread-safe 하게 사용하기 위해서 바로 이 Boost.Threads가 만들어 졌다...

많은 C++ 전문가들이 Boost 디자인을 위해 생각들을 내어놓았고 인터페이스는 바닥부터 차근 차근 설립한 기초공사부터 시작했단다. 걍 원래 있는 C 스레드 API 함수를 가져다 쓰는게 아니라 이말이다. 많은 C++의 특징들이 흡수되었고 (예로 생성자, 파괴자, 함수 객체, 템플릿등) 인터페이스를 보다 유연하게 만들었다. 현재 Boost가 돌아가는 환경은 POSIX, Win32, Mac 등이래요. 뭐 거의 크로스 플랫폼을 달성했다고 봐도...

Thread Creation

boost::thread는 std::fstream 클래스가 파일을 표현하는 것과 같은 방식으로 스레드의 실행을 표현한다. Default 생성자가 현재의 실행 스레드를 나타내는 객체를 생성한다. 오버로딩된 생성자는 입력 변수가 없고 리턴하는 것이 없는 함수 객체를 받는다. 이 생성자는 새로운 실행 스레드를 시작하는데 이는 결국 함수 객체의 호출이며 해당 함수의 호출이다.

첫눈에 보기에는 이 방식의 디자인이 기존 C의 방식보다 후져 보인다. 왜냐면 기존 C는 void 포인터를 새 스레드 생성시 데이터를 넘겨주기위해 사용할 수 있기 때문이다. 하지만 Boost.Threads는 함수 포인터 대신 함수 객체를 사용하기 때문에 이 함수 객체가 스레드에 필요한 데이터를 소유 할 수 있다. 이 접근법은 타입 점검을 정확히 하며 보다 유연하다. 다른 함수 라이브러리들, 예를 들어 Boost.Bind와 같은 것과 연동되면 이 방식은 어떤 형태의 데이터라도 (많든 적든) 새로 만들어진 스레드로 전달하기가 매우 쉽다. 

현재로써 Boost.Threads로 할수 있는건 많지는 않다. (이 글이 작성된게 2002년인걸 감안하면 이렇게 말할만도 하다.) 사실 딱 두개의 연산자만 사용할 수있다. (지금은 바뀌었겠지?) == 과 != 연산자를 이용하면 간단하게 같은 스레드인지 아닌지 확인 가능하다. 그리고 boost::thread::join을 이용하면 스레드가 작업을 다 할때까지 기다릴수 있다. 다른 스레드 라이브러리들은 스레드와 관련된 다른 작동을 할 수 있게 도와 준다. (예를 들면 우선순위 설정) 

아래 리스트 1은 아주 간단한 boost::thread 클래스의 사용을 보여준다. 새로운 스레드가 생성되고 이 스레드는 아주 간단한 hello() 함수를 호출한다. 이걸 하는 동안 main 스레드는 대기한다. 
#include <boost/thread/thread.hpp>
#include <iostream>

void hello() { std::cout << "Hello world, I'm a thread!" << std::endl; } int main(int argc, char* argv[]) { boost::thread thrd(&hello); thrd.join(); return 0; }

VS 2008으로 위 코드를 돌려봤더니 잘 돌아간다. 그리고 실행중에 디버깅을 해보면 아래 그림에 나온 것 처럼 hello() 함수 호출후 join 함수로 스레드 실행의 완료를 기다린후 return 0; 바로 직전에 브레이크 포인트를 자세히 보면 친절하게도 '이 프로세스나 스레드는 바로 직전에 변경되었습니다.'라고 알려준다. 참 친절하신 VS 2008. :)







 

Mutexes

멀티 스레드의 최대 약점은 자원 경쟁에 의한 오작동이다. 프로그램 짜본 사람이라면 누구나 알것이다. 이것은 두개 이상의 스레드가 동시에 공유된 자원에 접근하여 데이터를 변경할때 발생하는 데이터의 부정확성과 불일치를 말한다. 이것을 방지하기 위한 여러방법중 하나가 바로 Mutex 다른말로 하면Mutual Exclusion (상호 배타)이다. 이 뮤텍스는 오직 하나의 스레드만이 공유자원에 지정된 시간에 접근하도록 만든다. 고로, 스레드가 공유 자원에 접근하기 위해서는 우선 뮤텍스를 'lock' 해야 한다.즉, 공유자원이라는 집안에 들어가서 문을 걸어 잠그는 것이다. (다른 놈 못들어오게) 

뮤텍스의 컨셉은 여러가지가 있는데 Boost.Threads가 지원하는 가장 큰 두개의 카테고리는 Simple Mutex와 Recursive Mutex다. Simple Mutex는 말그대로 단순한 뮤텍스로써 오직 한번만 잠글수 있다. 만약 자신이 잠근 뮤텍스를 또 다시 잠글려고 하면 바로 데드락이 걸리고 이것은 '무한 대기(데드락)' 상태를 유발한다. 반면 Recursive Mutex (한국어로 말하면 재귀 뮤텍스이군)의 경우는 하나의 스레드가 뮤텍스를 여러번 잠글수 있으나 대신 반드시 잠근 횟수만큼 풀어야 다른 스레드가 공유자원을 사용할 수 있다는 것이다. 집에 들어와서 자물쇠를 현관문에 100개 달았으면 100개 다 풀어야 남이 들어온다는 이야기.

이 두가지의 카테고리 내부에서 또 여러가지 형태로 나뉘는데 이것은 어떤 식으로 뮤텍스를 잠그느냐에 따라 나뉜다. 세가지 방법으로 뮤텍스를 잠글수 있는데,
  1. 다른 스레드가 뮤텍스를 잠그지 않을때까지 대기
  2. 만약 다른 스레드가 뮤텍스를 잠궈놓은 상태라면 바로 리턴하기
  3. 다른 스레드가 뮤텍스를 잠그지 않을때까지 대기 하거나 혹은 일정 시간만 대기 하다가 리턴
최고의 뮤텍스 타입은 아무래도 recursive 타입인데 이 것은 위의 세가지 잠그기 방식을 모두 지원하기 때문이라는데... 반면 좋은 대신 오버헤드가 크다는 단점이 있다. 아무튼, 총 여섯 가지의 뮤텍스를 사용자가 선택가능하며 다음과 같다. 

boost::mutex
boost::try_mutex
boost::timed_mutex
boost::recursive_mutex
boost::recursive_try_mutex
boost::recursive_timed_mutex.

데드락은 매번 뮤텍스를 잠글때마다 잠근 횟수만큼 풀지 않았을때 발생한다. 이것이 가장 흔한 데드락의 한 종류인데 Boost.Threads는 이 데드락을 최대한 최소화 시킨다. (발생 할 수는 있다는 이야기) 어떤 뮤텍스이건 간에 직접적인 뮤텍스 잠금 및 해제 함수는 없다. 즉, 간접적인 방식으로 잠그고 푸는데 이것이 안전성을 높인다는 이야기. 이걸 Scoped Lock 이라고 한다는데 Douglas Schmidt, Michael Stal, Hans Rohnert, and Frank Buschmann. Pattern-Oriented Software Architecture Volume 2 Patterns for Concurrent and Networked Objects (Wiley, 2000) 를 참조하라고 해놨다. 헤헤, 거의 논문 수준이다. :)

아무튼, C++이 기본적으로 예외 발생시나 객체 파괴시 항상 파괴자를 호출하므로 파괴자에 뮤텍스를 풀어주는 장치를 둠으로써 이런 데드락을 줄인다는 이야기 란다. 다만 주의 할 것은 이 Scoped Lock 패턴이 비록 풀어주는 건 확실히 풀어주지만 예외가 발생해서 풀어졌을 경우 공유자원이 변경되었을 가능성이 있단다. 
 
아래의 코드는 간단한 뮤텍스 사용법을 보여준다.
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>

boost::mutex io_mutex;

struct count { count(int id) : id(id) { }

void operator()() { for (int i = 0; i < 10; ++i) { boost::mutex::scoped_lock lock(io_mutex); std::cout << id << ": " << i << std::endl; } }

int id; }; int main(int argc, char* argv[]) { boost::thread thrd1(count(1)); boost::thread thrd2(count(2)); thrd1.join(); thrd2.join(); return 0; }

위의 코드를 보면 thrd1과 thrd2라는 스레드를 생성하여 메인 스레드는 이 두 스레드가 끝날때까지 대기한다. 이 두 스레드는 count라는 구조체를 호출하는데 이 구조체 내부에 std::cout 함수가 호출되어 0에서 9까지의 숫자를 출력한다. 재미있는 것은 이 std::cout은 이른바 공유 자원이다. 화면에 글자를 출력해내는 함수는 한순간에 오직 하나의 스레드에 의해서만 점유되어야 함이 마땅하다. 고로 이 프로그램을 돌려보면 다음과 같이 각각의 스레드에 대해 0에서 9까지의 출력이 차례대로 나온다. 


헌데 만약 위 코드에서 뮤텍스를 잠그는 명령을 쏙 빼버리면 다음과 같은 결과가 나온다. 


잘 보면 thrd1의 "1"을 출력한후 스레드가 변경되어 thrd2의 "2: "를 출력한 후 다시 thrd1로 변경되어 ": 0"를 출력한 후 또 다시 thrd2로 변경되어 "0"을 출력한다. 이렇게 규칙성있게 출력되는 이유는 분명히 CPU가 공정하게 스레드에게 실행 시간을 나눠주기 때문일 것이다. 두 스레드가 같은 우선순위를 가지므로 둘이 똑같이 CPU 시간을 나눠 받는 것이다. 

그리고 위 코드를 다시 보면 함수 객체를 작성하는데 이거 매번 하려면 굉장히 불편하다. 이럴때 사용할 수 있는 것이 Boost.Bind란다. 다음 코드를 보면 새 함수 객체를 바인딩을 통해 값을 전달하여 생성하는 예를 보이고 있다. 

Listing 3: Using the Boost.Bind library to simplify the code in Listing 2

// This program is identical to
// listing2.cpp except that it
// uses Boost.Bind to simplify
// the creation of a thread that
// takes data.

#include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include <boost/bind.hpp> #include <iostream>

boost::mutex io_mutex;

void count(int id) { for (int i = 0; i < 10; ++i) { boost::mutex::scoped_lock lock(io_mutex); std::cout << id << ": " << i << std::endl; } } int main(int argc, char* argv[]) { boost::thread thrd1(boost::bind(&count, 1)); boost::thread thrd2(boost::bind(&count, 2)); thrd1.join(); thrd2.join(); return 0; }


Condition Variables

종종 걸어 잠그기 만으로는 충분하지 않은 경우가 있다. 즉 뮤텍스만으로는 해결 안되는 상황을 말한다. 어떤 자원이 있는데 그 자원을 사용하려면 반드시 특정 상태가 되어야 한다고 치자. 예를 들어 임의의 데이터가 네트워크를 통해서 들어오기를 기다려야 하는 상황이 있다면 뮤텍스는 이런 형태의 점검을 지원하기에는 적합하지 않다는 말이다. (아래를 보면 이해가 될것, 왜 뮤텍스로는 부족한지) 그래서 다른 형태의 동기화가 필요한데 이것이 바로 '조건 변수 (Condition Variable)'를 이용하는 것이란다.

하나의 조건 변수는 항상 뮤텍스와 공유 자원 사이에 접합 지점에서 사용이 된다. 하나의 스레드가 먼저 뮤텍스를 잠그고 난 다음 공유자원이 적합한 상태인지를 체크하게 된다. 만약 해당 상태가 아직 원하는 상태가 아니라면 스레드는 대기한다. 이 대기 상태에서 스레드는 뮤텍스를 풀어줌으로써 다른 스레드가 공유자원에 대해 남은 일을 처리하여 적합한 상태 (Ready 상태)로 변경할 수 있게 된다. 이것이 바로 조건 변수가 필요한 이유. 무한 대기가 아닌 조건 대기. 또한 이것은 스레드가 대기 상태에서 복귀할때 바로 뮤텍스를 걸어 잠그는 것까지 한다. 다른 스레드가 공유자원에 대한 작업을 마쳐서 조건 변수의 상태를 변경하게 되면 이것을 즉각적으로 대기하던 스레드에게 알려준다. 그로써 대기중인 스레드는 바로 복귀함과 동시에 완료된 공유자원에 뮤텍스를 이용해 잠근다. 

생각보다 현명한데? :) 조건 변수라고 하길레 그냥 정적 변수 하나 선언해 놓고 true / false 값 판단인줄 알았는데 제법 인공지능을 가지고 있다. 


#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <iostream>

const int BUF_SIZE = 10; const int ITERS = 100;

boost::mutex io_mutex;

class buffer{ public: typedef boost::mutex::scoped_lock scoped_lock; buffer(): p(0), c(0), full(0){ }

void put(int m){    scoped_lock lock(mutex);     if (full == BUF_SIZE)     {         {             boost::mutex::scoped_lock lock(io_mutex); 

           std::cout <<"Buffer is full. Waiting..."<< std::endl;         }         while (full == BUF_SIZE)             cond.wait(lock);     }

buf[p] = m; p = (p+1) % BUF_SIZE; ++full; cond.notify_one();

}

int get(){     scoped_lock lk(mutex);     if (full == 0){         {             boost::mutex::scoped_lock lock(io_mutex);

           std::cout <<"Buffer is empty. Waiting..."<< std::endl;         }         while (full == 0)             cond.wait(lk);     }

int i = buf[c]; c = (c+1) % BUF_SIZE; --full; cond.notify_one(); return i;

} private:     boost::mutex mutex;     boost::condition cond;     unsigned int p, c, full;     int buf[BUF_SIZE]; };

buffer buf;

void writer(){     for (int n = 0; n < ITERS; ++n){         {             boost::mutex::scoped_lock lock(io_mutex);             std::cout << "sending: "<< n << std::endl;         }

       buf.put(n);     } }

void reader(){     for (int x = 0; x < ITERS; ++x){         int n = buf.get();         {         boost::mutex::scoped_lock lock(io_mutex);         std::cout << "received: " << n << std::endl;         }     } }

int main(int argc, char* argv[]) {     boost::thread thrd1(&reader);     boost::thread thrd2(&writer);     thrd1.join();     thrd2.join(); return 0; 

}
}위 코드의 클래스는 FIFO 버퍼를 추상화했는데 내부 private 멤버 변수인 mutex를 사용해서 스레드에 안전하게 설계되었다. put과 get 함수는 condition variable을 사용하여 스레드가 적합한 상태로 공유자원이 변경되도록 기다리게 했다. 두 스레드가 만들어지면 하나는 100개의 정수를 이 버퍼에 넣고 다른 하나는 하나씩 빼낸다. 허나 이 버퍼는 최대 10개까지만 대기할 수 있으므로 두 스레드스 서로 기다려 준다. 잘보면 전역변수로 io_mutex를 선언하여 std::out에 대해서 뮤텍스를 사용함을 알수 있다. 

Thread Local Storage

 이 놈은 예전에 내가 다른 글에서 언급한 놈이다. http://diehard98.tistory.com/entry/프로그램-프로세스-스레드 를 보면 왜 TLS가 필요한지 설명하고 있다. 기본적으로 함수들은 재진입을 염두하지 않는다. 고로 하나의 스레드가 호출중인 함수를 다른 스레드가 또 호출하면 '불안정한' 상태가 될 수 있다는 의미. 재진입을 고려하지 않은 함수는 정적 데이터를 유지하는데 대표적인 예로 std::strtok가 있다. 이 놈은 재진입이 불가한데 왜냐면 함수가 호출되면 실행 동안에 정적 변수에 값을 저장해 놓기 때문이다. (고로 다른 스레드가 실행 와중에 다시 그 함수를 호출하여 사용하면 같은 정적 변수에 또 다른 값을 덮어 씌워 버릴것이다.)

이런 재진입이 불가한 함수들은 두가지 방법으로 재진입이 가능한 함수로 바꿀수 있다. 우선 첫번째는 포인터나 레퍼런스를 받아서 정적 변수를 사용하던 방식을 바꾸는 것이다. 예를 들어 POSIX의 strtok_r 함수는 std::strtok의 재진입을 가능하게 만든 함수로 이 함수는 입력 변수로 정적 변수를 사용하는 대신 char** 을 받는다. 이 해결법은 쉽고 좋다. 그러나 이렇게 하면 모든 공개된 인터페이스 (호출 방식)을 바꿔야 한다. 즉, 많은 코드의 변화를 가져온다는 이야기. 이 방법 말고 다른 방법인 두번째 방법이 바로 스레드에 독립적인 저장 공간을 주는 방식이다. 스레드의 독립적인 저장공간을 영어로 Thread Local Storage 혹은 Thread-Specific Storage라고 한다.

TLS는 각 스레드 별로 할당되는 고유 공간이다. 멀티스레드 라이브러리는 이 독립공간을 임의의 스레드가 접근할수 있도록 인터페이스를 제공한다. 고로 각각의 스레드는 스레드 객체의 고유 데이터를 소유하게 된다. 이 말은 다른 스레드가 접근 할 수 없다는 말이고, 즉, 자원 경쟁으로부터 자유롭다는 말. 문제는, 이 TLS가 일반 데이터 엑세스보다 느리다는 점. 하지만 첫번째 방법보다는 편한데 왜냐면 인터페이스를 안바꿔도 되니까 코드 변경이 필요없기 때문이다.

Boost.Threads는 boost::thread_specific_ptr이라는 스마트 포인터를 이용해서 TLS에 각 스레드가 접근 할 수 있도록 도와준다. 스마트 포인터란 참조된 횟수를 스스로 계산하여 자폭하는 영리한 포인터를 말한다. 각 스레드는 우선 이 스마트 포인터의 객체에 접근하는데 이때 이 값이 NULL인지 먼저 확인해야 한다. NULL이면 초기화가 필요하다는 말. 그리고 Boost.Threads 라이브러리는 스레드 종료시 이 TLS를 알아서 청소해준다. 왜냐면 스마트 포인터니까~

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/tss.hpp>
#include <iostream>

boost::mutex io_mutex; boost::thread_specific_ptr<int> ptr;

struct count{

    count(int id) : id(id) { }

void operator()(){     if (ptr.get() == 0)     ptr.reset(new int(0));

for (int i = 0; i < 10; ++i) {     (*ptr)++;     boost::mutex::scoped_lock lock(io_mutex);     std::cout << id << ": "<< *ptr << std::endl; }

}


int id;

};

int main(int argc, char* argv[]) {     boost::thread thrd1(count(1));     boost::thread thrd2(count(2));     thrd1.join();     thrd2.join(); return 0;

}

위 코드를 실행해 보면 각 스레드 별로 1에서 10까지 출력한다. 그리고 당근 std::out은 뮤텍스로 보호!

Once Routines

이제 남은 것은 딱 하나. 어떻게 생성자를 멀티스레드에 안전하게 만드는가다. 예를 들어 전역으로 사용되는 객체가 있다면 멀티스레드 환경에서 주의해야 할 것은 이 객체가 오직 한번만 생성자를 호출해야 하며 스레드들이 동시에 생성자를 호출하는 것을 막아야 한다.

이 것을 해결하는 방법은 이른바 "Once routine" 이라는 방식의 사용이다. 이 것을 이용하면 해당 함수나 변수는 프로그램에 의해 오직 한번만 호출된다. 만약 다수의 스레드가 이 함수를 동시에 호출한다면 그들중 오직 하나만이 이 함수에 접근할 수 있다. 이것을 가능하게 해주는 방법은 바로 랩핑함수를 이용해서 한번 더 점검을 하는 거란다. 고로 멀티 스레드 환경에서 '오직 한번' 초기화하기 문제는 해결되었다. boost::call_once를 이용하면 되고 플레그 타입인 boost::once_flag를 BOOST_ONCE_INIT 매크로를 이용해 초기화 하면 된다네.

Listing 6: A very simple use of boost::call_once

#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <iostream>

int i = 0; boost::once_flag flag = BOOST_ONCE_INIT;

void init() {     ++i; }

void thread1() {     boost::call_once(&init, flag); }

int main(int argc, char* argv[]) {     boost::thread thrd1(&thread1);     boost::thread thrd2(&thread1);     thrd1.join();     thrd2.join();     std::cout << i << std::endl; return 0; }

뭐 위 코드를 보면 flag를 선언할때 BOOST_ONCE_INIT 매크로 사용했고 전역 변수 i를 두개의 스레드가 동시에 접근하는데 둘 다 call_once로 호출하므로 두 스레드중 오직 하나만 접근 하여 초기화 한후 값을 하나 증가 시킨다. 고로 다른 스레드는 해당 함수를 더 이상 호출 할 수 없으므로 출력 값으로는 1이 출력된다. 만약 두 스레드가 모두 변수에 호출가능 했다면 i 값은 2가 되어야 한다.

The Future of Boost.Threads

Boost.Threads를 위한 몇가지 계획이 있는데 추가될 놈으로 boost::read_write_mutex가 있단다. 이 것은 멀티 스레드들이 공유자원을 동시에 읽기 가능하게 하고 단, 쓸때는 한놈만 쓰게 한다. 그리고 추가로 boost::thread_barrier 라는 놈을 만들건데 이 놈은 특정 스레드들이 모두 특정한 위치까지 들어오도록 기다린단다. 흠... 용이하겠는데? 그리고 또 boost::thread_pool을 계획중인데 이 녀석은 스레드를 매번 생성 파괴하지 않고 짧은 실행을 비동기로 할 수 있게 해주는 놈이란다. 찾아보니 이 놈들 벌써 구현됬다... ㅋㅋㅋ

그리고 이 Boost.Threads는 차기 C++ 표준에 들어갈 수도 있다는 말과 함께 이 긴 글을 마무리한다...

추가로 참조된 책 및 웹사이트, 논문등

Notes

[1] The POSIX standard defines multithreaded support in what’s commonly known as the pthread library. This provides multithreaded support for a wide range of operating systems, including Win32 through the pthreads-win32 port. However, this is a C library that fails to address some C++ concepts and is not available on all platforms.

[2] Visit the Boost website at <http://www.boost.org>.

[3] See Bjorn Karlsson’s article, “Smart Pointers in Boost,” in C/C++ Users Journal, April 2002.

[4] Douglas Schmidt, Michael Stal, Hans Rohnert, and Frank Buschmann. Pattern-Oriented Software Architecture Volume 2 Patterns for Concurrent and Networked Objects (Wiley, 2000).


이제 내가 이야기를 할 차례다. 일단 이 글쓴이에게 감사하는 바이다. 2002년에 작성된 글이라 오래된 느낌이 있지만 매우 영리하고 정확한 표현으로 이해를 돕는다. 그리고 중간중간 효과적인 소스코드로 더더욱 이해가 쉽게 해주었다.

Boost 라는 그 자체에 대해서 경이로움을 느낀다. C++이 멀티스레드에 약하다는 것은 잘 알고 있었지만 그것을 이렇게 잘 커버해주는 이런 대형 라이브러리가 있는지는 정확히는 몰랐다. 대단하다...

스레드의 생성과 선언 및 관리가 운영체제마다 다르기 때문에 윈도우에서 작성한 코드는 유닉스에서 안돌아 가지만 이 Boost 라이브러리를 이용하면 코드 변경 없이 가능하겠다. 그리고 스레드마저 객체화하여 클래스로 표현하므로 객체 지향에도 걸맞는다. 

오버헤드가 좀 있겠지만 객체로 표현한다는 장점에 비하면 적지 않나 싶다. 이 글이 너무 길어지면 곤란하므로 여기까지만 쓰겠다. 


반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::random  (0) 2013.01.29
Boost::mpl  (0) 2012.12.25
boost::weak_ptr  (0) 2012.11.24
boost::shared_ptr  (0) 2012.11.18
boost::function  (0) 2012.11.13
반응형

http://jacking.tistory.com/590


괴로운 메모리 관리 - shared_ptr / weak_ptr

 

C/C++ 에서 메모리 관리는 프로그래머에게 맡겨져 있습니다귀찮은 것으로 프로그래머의 약간의 실수가 큰 사고로 연결 되는 경우가 허다합니다.

  

 

포인터는 귀찮다

 

string* p = new string( "one" );

string* q = new string( "two" );

p = q; // p,q 모두 "two" 를 가리킨다. "one"은 미아

delete p;

delete q; // "two"를 다중 delete!

 

 

 

std::auto_ptr의 한계

 

표준 C++라이브러리는 메모리 관리를 편하게 하는 std::auto_ptr 를 제공하고 있습니다.

    

auto_ptr 이라면

#include

#include ring>

#include <memory> // std::auto_ptr<T>

 

using namespace std;

 

class item {

private :

string value_;

public :

 item( const char * v= "???" ) : value_(v) 

 {

   cout << "item(" << value_ << ") ctor\n" ;

  }

  ~item() { cout << "item(" << value_ << ") dtor\n" ; }

  string value() const { return value_; }

};

 

int main() 

{

   auto_ptr<item> p( new item( "one" ));

   auto_ptr<item> q( new item( "two" ));

   p = q; // p는 가리키고 있었  "one" delete, "two"를 가리킨다. q null  된다.

   cout << "p points to " << (p.get() ? p->value() : "(null)" ) << endl;

   cout << "q points to " << (q.get() ? q->value() : "(null)" ) << endl;

}

 

실행 결과 >

item(one) ctor

item(two) ctor

item(one) dtor

p p oints to two

q points to (null)

item(two) dtor

 


실행 결과가 나타내 보이는 대로 constructor 와 소멸자의 수가 일치하고 있을 테니 delete 잊거나 다중 delete가 발생하지 않는 것을 압니다auto_ptr은 소멸 시에 그것이 가리키는 포인터를 delete 하므로 명시적으로 delete 할 필요가 없습니다.

다만  auto_ptr 사이의 복사(대입)를 하면 포인터의 소유권(=삭제 책임)이 이동 하여 복사 처(source)에서는 포인터가 없어집니다(실행 결과의 q "two"를 가리키고 있지 않아요). 그 때문에 복수의 auto_ptr가 하나의 인스턴스를 가리켜 공유할 수 없습니다.

    


auto_ptr 에서는 인스턴스를 공유할 수 없다

class person {

string name_;

public :

person(string n) : namae_(n) {}

auto_ptr child; // 자식

};

 

person sazae( "소라" );

person masuo( "마스오" );

auto_ptr tara( new person( "타라" ));

// "타라" "소라" "마스오"의 자식로 하고 싶지만

sazae.child = tara; // 이 순간 "타라"의 소유권이 tara로부터

// sazae.child로 이동(양도된다)

masuo.child = tara; // masuo.child  "타라"를 가리킬 수 없다

 

 

new된 인스턴스를 자동적으로 delete 해 주는 auto_ptr 은 편리 한 것은 틀림 없습니다만 이 제한이 있기 때문에 용도가 한정되어 버립니다.

 

 

std::tr1::shared_ptr - 공유 포인터

 

TR1에서 새롭게 추가된 shared_ptr은 참조 카운트라고 하는 것으로 인스턴스를 관리합니다shared_ptr은 그 내부에 그 인스턴스를 참조하고 있는 shared_ptr의 총 수를 보관 유지하고 있습니다 shared_ptr 의 소멸자는 내부의 참조수를 -1 하여 그것이 0이 되었을 때 인스턴스가 어디에서도 참조되지 않게 되었다 라고 판단 하고 인스턴스를 delete 합니다.

     

shared_ptr

#include <iostream>

#include <string>

#include <boost/tr1/memory.hpp> // std::tr1::shared_ptr

 

using namespace std;

 

class item {

private :

string value_;

public :

item( const char * v= "???" ) : value_(v) {

cout << "item(" << value_ << ") ctor\n" ;

 }

~item() { cout << "item(" << value_ << ") dtor\n" ; }

string value() const { return value_; }

};

 

int main() 

{

   // p1  "something"을 가리킨다. 참조수:1

   tr1::shared_ptr<item> p1( new item( "something" ));

   cout << "p1->value() = " << p1->value() << endl;

   {

      // p2 "something"을 가리킨다. 참조수:2

      tr1::shared_ptr<item> p2 = p1;

      cout << "p2->value() = " << p2->value() << endl;

      // 여기서 p2가 사라진다. 참조 회수:1

   }

   cout << "p1->value() = " << p1->value() << endl;

   // 여기서 p1이 사라진다. 참조수:0되어 "something"  delete된다

}


< 실행 결과 > 

item(something) ctor

p1->value() = something

p2->value() = something

p1->value() = something

item(something) dtor


std::tr1:weak_ptr 약 참조 포인터 shared_ptr 을 사용하는 것에 의해서 번잡한 메모리 관리 로부터 해방됩니다만 이것으로도 아직 순환 참조 라고 하는 문제가 남아 있습니다.

 


순환 참조란

#include <iostream>

#include <string>

#include <boost/tr1/memory.hpp> // std::tr1::shared_ptr

 

class Person {

public :

string name; // 이름

tr1::shared_ptr spouse; // 배우자

Person(string n) : name(n) {}

void info() const {

cout << "My name is " << name

<< " and my spouse is " << spouse->name << endl;

}

};

 

int main() 

{

   // one  "adam"을 가리킨다참조수:1

   tr1::shared_ptr<Person> one( new Person( "adam" ));

   {

      // two  "eve"을 가리킨다참조수:1

      tr1::shared_ptr<Person> two( new Person( "eve" ));

      one->spouse = two; // "adam"의 아내는 "eve" 참조수:2

      two->spouse = one; // "eve"의 남편은 "adam" 참조수:2

      one->info();

      two->info();

      // 여기서 two가 사라진다. 참조수:1 ... 0은 아니기 때문에 "eve" delete 되지 않는다

   }

   one->info();

   // 여기서 one이 사라진다. 참조수:1 ... 0은 아니기 때문에 "adam"는 delete 되지 않는다

}

 

실행 결과 >

My name is adam and my spouse is eve

My name is eve and my spouse is adam

My name is adam and my spouse is eve

 

이 예와 비슷하게 복수의 shared_ptr 이 서로를 서로 참조해 루프를 형성하면(순환 하는참조수가 0이 되는 것이 없기 때문에 인스턴스가 delete 되지 않고 남아 버립니다.

 

이 문제를 해소하기 위해 TR1은 한층 더 하나 더 weak_ptr을 제공합니다weak_ptr은 shared_ptr 가 보관 유지하는 참조수의 증감에 관여하지 않습니다또한 weak_ptr의 멤버 expired()에 의해서 인스턴스의 소실을 알 수 있습니다.

     


weak_ptr에 의한 해결

#include <iostream>

#include <string>

#include <boost/tr1/memory.hpp>

// std::tr1::shared_ptr, std::tr1::weak_ptr

 

class Person {

public :

string name;

tr1::weak_ptr<spouse> spouse;

Person(string n) : name(n) {}

void info() const {

cout << "My name is " << name

<< " and my spouse " ;

if ( spouse.expired() ) // 인스턴스의 유무를 판단한다

cout << "has gone...\n" ;

else

cout << spouse.lock()->name << endl;

}

};

 

int main() 

{

   // one "adam"을 가리킨다참조수:1

   tr1::shared_ptr<Person2> one( new Person2( "adam" ));

   {

      // two "eve"를 가리킨다참조수:1

      tr1::shared_ptr<Person2> two( new Person2( "eve" ));

      // weak_ptr은 참조수의 증감에 관여하지 않는다

      one->spouse = two; // "adam"의 아내는 "eve" 참조수:1

      two->spouse = one; // "eve"의 남편은 "adam" 참조수:1

      one->info();

      two->info();

      // 여기서 two가 사라진다. 참조수:0  되어 "eve"  delete 된다

   }

   one->info();

   // 여기서 one이 사라진다. 참조수:0  되어 "adam"  delete 된다

}

 

실행 결과 >

My name is adam and my spouse eve

My name is eve and my spouse adam

My name is adam and my spouse has gone...

정리

차기 C++규격 「C++0x」 에서 확장 예정의 라이브러리 「TR1」로부터 array와 shared_ptr /weak_ptr를 소개했습니다이것들을 활용하는 것으로 C++에서 귀찮은 메모리 관리가 훨씬 편해지겠지요.

TR1에는 그 외에도 편리한 클래스가 다수 수록되고 있습니다속편을 기대하세요.



원본 : http://codezine.jp/a/article/aid/1937.aspx

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

Boost::mpl  (0) 2012.12.25
boost::thread  (0) 2012.12.25
boost::shared_ptr  (0) 2012.11.18
boost::function  (0) 2012.11.13
boost::unordered_set  (0) 2012.11.13
반응형



http://breaklee.blog.me/60137887986

shared_ptr 은 간단하게 설명하자면, 가리키고 있는 객체의 수를 관리(참조 카운트)하고, 

참조하고 있는 객체의 수가 0 이되면 자동으로 삭제시켜주는 smart pointer 입니다.


소멸자 보면, _Decref() 라는 함수를 호출하고 있습니다. 뭐구현마다 조금씩 차이는 있겠지만,

내부적으로 ref count  관리하고 하나씩 줄여주는 역할을 합니다.

당연히, ref count  0  되면제어하고 있는 객체를 delete 합니다.


 ~shared_ptr()

      {       // release resource

              this->_Decref();

      }

           

void _Decref()

{       // decrement use count

        if (_MT_DECR(_Mtx, _Uses) == 0)

        {       // destroy managed resource, decrement weak reference count

               _Destroy();

               _Decwref();

        }

 }


     

오버로딩 된 생성자를 살펴보면 std::auto_ptr 을 인자로 받는 생성자가 보입니다auto_ptr release()  호출합니다. 

shared_ptr  공유하려는 목적으로 사용한다면 의도와는 다르게 auto_ptr 은, 그 후로는 사용할  없게 됩니다.

auto_ptr 참조 http://breaklee.blog.me/60123428473 ]

 

template<class _Ty2>

      explicit shared_ptr(auto_ptr<_Ty2>& _Other)

      {       // construct shared_ptr object that owns *_Other.get()

               this->_Reset(_Other);

      }

 

template<class _Ty2>

      void _Reset(auto_ptr<_Ty2>& _Other)

      {       // release resource and take _Other.get()

               _Ty2 *_Px = _Other.get();

               _Reset(_Px, new _Ref_count<_Elem>(_Px));

               _Other.release();

      }



한가지 재미는건, bool type 으로 캐스팅  경우객체의 상태를 질의   있다는 건데요.

 

operator _STD _Bool_type() const

      {       // test if shared_ptr object owns no resource

              return (this->_Get() != 0 ? _CONVERTIBLE_TO_TRUE : 0);

      }


  

결국엔 객체의 주소값으로 TRUE 임을 알려주고 있습니다간단한 이해를 위해서 boost  잠시 보시면


 operator bool () const

{

return px != 0;

}


 

그냥 shared_ptr 객체가 가리키고 있는 곳이  아니면 true  리턴하게 되어 있습니다.

오류나 의도치 않은 연산의 방지를 위해(표준 때문에), tr1에서는 멤버 함수의 포인터를 반환하여 예방하고 있습니다.

[출처] shared_ptr|작성자 breaklee







http://humnya.egloos.com/2913729


shared_ptr을 c++ 형식으로 타입 캐스팅 하고 싶을 때는

static_pointer_cast<type> var;
dynamic_pointer_cast<type> var;
static_pointer_cast<type> var;



http://crowmaniac.net/boostshared_ptr%EC%97%90-%EA%B4%80%ED%95%B4/

3. shared_ptr의 파괴동작.

shared_ptr을 단순히 new/delete를 이용해 생성/파괴하는 객체에만 사용할 수 있다는 생각은 크나큰 오산입니다. Custom Destructor를 세팅할 수 있게 해주는 기능은 shared_ptr의 가능성을 대폭 증가시켜 줍니다. :)

01#include <boost/shared_ptr.hpp>
02// 사실 싫어하는 예이지만, HANDLE을 예로 들고 싶기에 어쩔수.. 없;;
03#include <windows.h>
04typedef boost::shared_ptr<void> HANDLESP;
05 
06void test8()
07{
08HANDLE h = ...(뭐든 핸들을 받아온다)...
09HANDLESP hsp = HANDLESP(h, CloseHandle);
10}// hsp가 파괴될때 CloseHandle(h)가 호출된다.

hsp를 생성할때 보면, 뒤쪽에 CloseHandle이란 함수를 넣어주는 것을 발견할 수 있습니다. CloseHandle의 위치에는 HANDLE(정확히는 void*)을 매개변수로 받는 호출가능한 C++객체는 무엇이든 올 수 있습니다. :)

즉, 객체가 C++ 표준인 new/delete를 이용해 할당되지 않더라도 파괴될때 호출할 호출가능한 객체를 지정해주면, delete대신 그 함수를 통해 객체를 파괴하게 되지요.

DLL 사이에서 객체를 주고 받을 때도 매우 유용합니다. DLL A에서 생성한 객체를 DLL B에서 파괴할 경우 문제가 발생하기 때문에, A의 인터페이스에 객체를 삭제하는 함수를 등록시켜서 쓰는 것이 일반적인데, 이런 경우에도 객체를 삭제하는 함수를 파괴시 호출할 함수로 지정해주면 간단히 shared_ptr을 적용할 수 있는 것이지요. 이때, 전에 설명했던 boost::bind가 큰 힘을 발휘하는 경우가 많답니다.




http://harmonize84.tistory.com/130


shared_static_cast


My Program-*/C+ 2009/11/16 13:21
  1. class CBase  
  2. {  
  3. };  
  4.   
  5. class CDerived : public CBase  
  6. {  
  7. };  
  8.   
  9. std::map<int, boost::shared_ptr<CBase>> mapTest;  
  10.   
  11.   
  12. boost::shared_ptr<CDerived> TestFunc(void)  
  13. {  
  14.     boost::shared_ptr<CBase> pTest(new CDerived);  
  15.   
  16.     mapTest.insert(std::map<int, boost::shared_ptr<CBase>>::value_type(0, pTest));  
  17.   
  18.     std::map<int, boost::shared_ptr<CBase>>::iterator iter = mapTest.find(0);  
  19.   
  20.     return boost::shared_ptr<CDerived>(static_cast<CDerived*>(iter->second.get()));      // 문제의 장소  
  21. }  
  22.   
  23. int main(void)  
  24. {  
  25.     boost::shared_ptr<CDerived> pInv = TestFunc();  
  26.   
  27.     return 0;  
  28. }  


인터페이스 클래스를 설계하면서 부딪힌 문제이다.

위 코드는 2가지 문제가 있다. 
(일단 위 코드는 런타임 에러로 _BLOCK_TYPE_IS_VALID_가 나는데 이는 포인터가 잡혀 있지 않다는 의미)

첫번째는 shared_ptr의 임시객체에 map에 있는 shared_ptr의 원시포인터를 반환한다는 점

두번째는 shared_ptr에 담긴 객체의 포인터를 static_cast로 변환한다는 점이다.

사실 이 두가지 문제는 하나로 귀결되는데 그것은 boost에서 지원하는 캐스팅을 통하여

이 값을 그대로 넘겨주는 방법이 그것이다.

이 방법을 몰라서 객체의 포인터를 캐스팅변환을 통하여 임시객체에 넣고 그것을 반환하는 형식의

코드를 작성했는데 임시객체에 들어감으로써 그것은 map에서 가지고있는 카운팅이 올라가는 것이 아닌

또다른 하나의 스마트 포인터가 생성된 것이다. 이미 해제된 메모리에 대해 해제를 시도하니 에러는 당연지사

아래 코드는 위의 문제를 해결한 코드이다.

  1. boost::shared_ptr<CDerived> TestFunc(void)  
  2. {  
  3.     boost::shared_ptr<CBase> pTest(new CDerived);  
  4.   
  5.     mapTest.insert(std::map<int, boost::shared_ptr<CBase>>::value_type(0, pTest));  
  6.   
  7.     std::map<int, boost::shared_ptr<CBase>>::iterator iter = mapTest.find(0);  
  8.   
  9.     return boost::shared_static_cast<CDerived>(iter->second);  
  10.     //return boost::shared_ptr<CDerived>(static_cast<CDerived*>(iter->second.get()));        // 문제의 코드  
  11. }  


이 문제때문에 2일을 허비했다. 중간에 결혼식도 있고 하여 정상적인 작업이 불가능 했지만.





http://blog.naver.com/jungwan82?Redirect=Log&logNo=20120508129


클래스내에서 자신에 대한 shared_ptr 리턴하기





아래처럼 쓰면 안되고..


#include <iostream>

#include <boost/shared_ptr.hpp>


class A

{

public:

boost::shared_ptr<A> test()

{

boost::shared_ptr<A> pFromThis(this); // <- this part is dangerous.

return pFromThis;

}

};


int main(int argc, _TCHAR* argv[])

{

boost::shared_ptr<A> p(new A);

boost::shared_ptr<A> p2 = p->test();

std::cout << p.use_count() << std::endl;

p->test();


getchar();

return 0;

}


위의 용법의 특이점은 this 를 이용해서  shared_ptr를 만들어낸다는 것이다. cout에 출력되는 use_count()값은 기대값인 2가 아니라 1이 되어 버리는데 이유는 this가  A const* 형이기 때문인 것으로 추정된다. 위의 예제에서 우리는 shared_ptr<A>의 인스턴스가 2개 존재하는 것으로 기대하는데 use_count()가 1이라는 것은 아직도 필요한 포인터가 delete 되어버릴 수 있다는 것을 의미한다.


해결방법은 아래와 같다.


#include <iostream>

#include <boost/enable_shared_from_this.hpp>

#include <boost/shared_ptr.hpp>


class A : public boost::enable_shared_from_this<A>

{

public:

boost::shared_ptr<A> test()

{

return shared_from_this();

}

};


int main(int argc, _TCHAR* argv[])

{

boost::shared_ptr<A> p(new A);

boost::shared_ptr<A> p2 = p->test();


std::cout << "shared_count = " << p.use_count() << std::endl;



getchar();


return 0;

}




반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::thread  (0) 2012.12.25
boost::weak_ptr  (0) 2012.11.24
boost::function  (0) 2012.11.13
boost::unordered_set  (0) 2012.11.13
Boost::[bind, mem_fn ] 과 STL , 멤버함수 조합사용  (0) 2012.11.13
반응형



http://blog.naver.com/waraccc/116732322



boost::function 은 일종의 함수포인터처럼 사용이 가능합니다.( function wrapper ) 

과거에 사용했었던 함수 포인터를 대처해서 사용이 가능하죠 뿐만 아니라 ( 함수 + 추가 정보 )를 패키지로 저장해서 

들고 다기는것도 가능합니다.( 라고는 얘기 하는데 솔직히 무슨 소리인지는 모르겠네요 -ㅅ- )


예제를 쌈빡하게 보도록 하죠...

함수포인터를 사용해서 해외 코드 관리를 할수 있는 간략한 예제를 한번 boost::function을 사용하여 

변경한 예제를 보여드리겠습니다.


#include <boost/function.hpp>

#include <iostream>


using namespace std;


class DoSomething_CN

{

public:

 void operator()()

 {

  cout<<"Dosomething_CN"<<endl;

 }

};


class DoSomething_KR

{

public:

 void operator()()

 {

  cout<<"DoSomething_KR"<<endl;

 }

};


class DoSomething_US

{

public:

 void operator()()

 {

  cout<<"DoSomething_US"<<endl;

 }

};


int _tmain(int argc, _TCHAR* argv[])

{

 boost::function<void()> selectfunc;

 int nLangCode = 0;


 cout<<"숫자를 입력하세요"<<endl;

 cin>>nLangCode;


 switch ( nLangCode )

 {

 case 0:

  selectfunc = DoSomething_CN();

  selectfunc();

  break;

 case 1:

  selectfunc = DoSomething_KR();

  selectfunc();

  break;

 case 2:

  selectfunc = DoSomething_US();

  selectfunc();

  break;  

 } 


 system("PAUSE");

 return 0;

}


이렇게 사용하면 함수 포인터를 대신하여 사용할 수 있습니다.

갑자기 이 예제를 보니 불과 한달전인가요? 어이없는 C모사에서 PD가 지뿔 아는것도 없으면서

함수 포인터를 절대로 사용하지 말라면서( 해외 코드 관리 부분이였죠 그때도 ) 클래스로 만들어 달라는게

생각나는군요 ㅋㅋㅋ 머 이런식으로 사용도 가능하고

클래스 안에 클래스 맴버 함수도 접근이 가능합니다.

어떤식으로 가능하냐면


class CTest

{

public:

 void print( int n )

 {

  std::cout << "클래스 함수 입력값: " << n << std::endl;

 }

};


int _tmain(int argc, _TCHAR* argv[])

{

 CTest ctest;


 boost::function< void( CTest*, int ) > classfunc;                              //boost::function< void( CTest*, int x ) > classfunc;로 변경가능

 classfunc = &CTest::print;

 classfunc( &ctest, 10 );


 boost::function< void(int) > classfunc2;                                          //boost::function< void(int x) > classfunc2;로 변경가능

 classfunc2 = std::bind1st( std::mem_fun( &CTest::print), &ctest );      

 classfunc2( 17 );


 system("PAUSE");

 return 0;

}


이런식으록 가능합니다. 머 주석처리 방식으로 다른 호출 방법을 적었는데

이건 머 좀 더 명확하게 해주는 방식인지라 타이핑 하기 귀춘하시면 생략하셔도 됩니다.

이상 boost::function 사용법을 간략하게 알아보았습니다. 추후에 ( 함수 + 추가 정보 )를 패키지로 저장해서 

들고 다기는것도 가능하다라는 방식도 조사해서 기재해보도록하죠 -ㅅ-;



반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::weak_ptr  (0) 2012.11.24
boost::shared_ptr  (0) 2012.11.18
boost::unordered_set  (0) 2012.11.13
Boost::[bind, mem_fn ] 과 STL , 멤버함수 조합사용  (0) 2012.11.13
boost::bind  (0) 2012.11.13
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..

by 송정헌


boost 에도 unordered_set 이 있으며 사용법은 유사함






http://blog.naver.com/tchar/150105434685



아래의 예를 보자.

#include <memory>
#include <unordered_set>

void main()
{
 std::unordered_set< std::shared_ptr<int> > s;
 s.insert( std::shared_ptr< int >( new int(10) ) );
}

해시 컨테이너중 하나인 unordered_set 에 shared_ptr< int > 타입을 사용하였다. 컴파일 해보면 오류가 발생한다.

 

해시 컨테이너는 템플릿 인수로 해시 함수객체의 타입을 받고, 디폴트로 std::hash<T> 가 사용된다. 대략 다음처럼 선언되어 있다.

// functional 헤더

template< typename T >
class hash : public unary_function< T, size_t >
{

public:

 size_t operator()( const T &value ) const
 { ... (size_t) value ... }
};

이외에도 T를 T*나 double 등으로 특수화한 버전들이 여럿 존재하고, 그것들은 위의 함수객체를 이용하도록 작성되어 있다. 안타깝게도 shared_ptr에

 

대한 특수화 버전은 제공되지 않고, 그래서 위의 함수객체가 직접 사용된다. opreator() 함수의 몸체를 보면, 값을 size_t로 형변환함을 알 수 있다.

 

그러나 T가 shared_ptr일 때, shared_ptr은 size_t로의 암시적 형변환을 제공하지 않는다. 그래서 shared_ptr 타입에 대해서 해시 컨테이너의

 

해시 함수를 디폴트로 했을 때 오류가 발생하게 되는 것이다. 이를 해결하기 위해 직접 shared_ptr 의 특수화 버전을 제공하면 된다.

 

아래는 위에서 오류가 발생했던 코드에 특수화 버전을 추가해서 오류가 없도록 한 것이다.

#include <memory>
#include <unordered_set>

template< typename T >
class std::hash< std::shared_ptr< T > > : public unary_function< shared_ptr< T >, size_t >
{

public:

 size_t operator()( const shared_ptr< T > &value ) const
 { return hash< T* >()( value.get() ); }
};

void main()
{
 std::unordered_set< std::shared_ptr<int> > s;
 s.insert( std::shared_ptr< int >( new int(10) ) );
}

shared_ptr 로 특수화한 함수객체의 몸체를 보면, shared_ptr< T >::get() 함수를 이용하여 포인터를 얻고 그 포인터를 T* 로 특수화된 함수객체에

 

넘기고 있다. 이제 제대로 컴파일되는 것을 확인할 수 있다.

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::shared_ptr  (0) 2012.11.18
boost::function  (0) 2012.11.13
Boost::[bind, mem_fn ] 과 STL , 멤버함수 조합사용  (0) 2012.11.13
boost::bind  (0) 2012.11.13
boost::mem_fn  (0) 2012.11.13
반응형



http://cafe.naver.com/ecpp/9


 

멤버함수의 포인터 형 타입선언과 포인터변수 선언과 그 간단한 사용 예를 올립니다.

 

대략 모양새는 알고 있지만 쓸데 마다 헷갈리더군요아래의 코드 사용 예 정도만 외워둔다면 멤버함수포인터에서는 별로 어려움이 없으리라 봅니다.

 

 

#include <iostream>

 

using namespace std;

 

//----------------------------------------------------------------

 

class Cfoo

{

public:

             Cfoo() : doit_count(0), domore_count(0) {}

 

             int DoIt( float a, char b, char c ) {

                           cout << "DoIt-" << a << b << c << endl;

                           return doit_count++;

             }

             int DoMore( float a, char b, char c ) {

                           cout << "DoMore-" << a << b << c << endl;

                           return domore_count++;

             }

 

private:

             int doit_count;

             int domore_count;

};

 

//----------------------------------------------------------------

 

void main()

{

             typedef int (Cfoo::*pt2Member)(float, char, char);

 

             pt2Member funcArr1[10] = {NULL};

 

             int (Cfoo::*funcArr2[10])(float, char, char) = {NULL};

 

             funcArr1[0] = funcArr2[1] = &Cfoo::DoIt;

             funcArr1[1] = funcArr2[0] = &Cfoo::DoMore;

 

             Cfoo instance;

             cout << (instance.*funcArr1[0])(1, 'a', 'b') << endl;

             cout << (instance.*funcArr1[1])(2, 'a', 'b') << endl;

  

             // cout << (instance.*funcArr1[2])(3, 'a', 'b') << endl; - Runtime Error!

  

             cout << (instance.*funcArr2[1])(34, 'a', 'b') << endl;

             cout << (instance.*funcArr2[0])(89, 'a', 'b') << endl;

}

 

그럼 std::mem_fun  std::mem_fun_ref 그리고 boost::mem_fn 에 대해 알아보자.

 

mem_fun 은 객체포인터에 적용가능하고mem_fun_ref 는 객체에 적용된다아래 예제를 작성하면서도 상당히 헷갈려서 컴파일에러 땜시 많은 고생을 하였다ㅡㅡ;;

 

boost::mem_fn 은 이런 구분이 없이 사용 가능하다역시 boost 가 좋다!

 

mem_fun1 이란 것도 있는데 이 또한 bind1st, bind2nd 와 같이 역시 파라메타의 개수에 제한을 받게 된다.

 

역시 boost 는 이런 제한과 구분 없이 하나를 사용하여 다 적용이 가능하다.

 

#include <vector>

#include <iostream>

#include <functional>

#include <algorithm>

#include <boost/bind.hpp>

#include <boost/mem_fn.hpp>

 

 

class Cfoo

{

public:

             Cfoo( ) : count(0) {}

             Cfoo( int n ) : count(n) {}

             void print()

             {

                           std::cout << "print - " << count++ << std::endl;

             }

             void print_n( int n )

             {

                           std::cout << "print_n - " << count++ << std::endl;

             }

private:

             int count;

};

 

const static TEST_COUNT = 3;

 

int incrementFunc( int& n ) { return n++; }

 

void main()

{

             using std::for_each;

 

             std::vector<Cfoo> vec;

             std::fill_n( std::back_inserter(vec), 5, Cfoo(1) );

 

             for_each( vec.begin(), vec.end(), std::mem_fun_ref( &Cfoo::print ) );

             for_each( vec.begin(), vec.end(), boost::mem_fn( &Cfoo::print ) );

 

             //-------------------------------------------------------------------------------------------

             // 함수인자값을 전달하려면, bind 를 이용하라.

             //-------------------------------------------------------------------------------------------            

 

             // 넘 복잡다.

             for_each( vec.begin(), vec.end(), std::bind2nd( std::mem_fun1_ref<void, Cfoo, int>( &Cfoo::print_n ), 111) );

 

             // 오, 템플릿인자들이 생략가능하다.

             for_each( vec.begin(), vec.end(), std::bind2nd( std::mem_fun1_ref( &Cfoo::print_n ), 222) );

 

             // boost 형식으로 바꾸면 아래와 같이 되기도 합니다.

             for_each( vec.begin(), vec.end(), boost::bind( boost::mem_fn( &Cfoo::print_n ), _1, 222) );

 

             // 간단히 바꿀수 있다. 역시 boost 가 좋다.

             for_each( vec.begin(), vec.end(), boost::bind( &Cfoo::print_n, _1, 333 ) );

 

             //-------------------------------------------------------------------------------------------

             // bind 를 할때 함수인자를 가변값으로 줄 수 있는 방법 ( boost::bind 의 한계 )
             //-------------------------------------------------------------------------------------------            

 

             int i = 0;

 

             // 삐꾸예제 - 동작이 되면 좋겠지만, 원하는 대로 동작하지 않는다.
             for_each( vec.begin(), vec.end(), boost::bind( &Cfoo::print_n, _1, i++ ) );
 
             // boost::bind 를 이용한 예제 - 함수를 만들고 다시 bind 시켜주어야 한다.
             for_each( vec.begin(), vec.end(), boost::bind( &Cfoo::print_n, _1, boost::bind( incrementFunc, i ) ) );

 

             // boost::lambda 를 이용한 예제 - boost::lambda 를 이용하면 한 문장으로 가능하다. 가장 진화된 형태

             for_each( vec.begin(), vec.end(), boost::lambda::bind( &Cfoo::print_n, boost::lambda::_1, boost::lambda::var( i )++ ) );

 

             //------------------------------------------------------------------------            

             // 아래와 같이 배열의 포인터도 알고리즘에 바로 적용가능하다.

             //------------------------------------------------------------------------

 

             Cfoo foo_[TEST_COUNT];

             for_each( foo_, foo_+TEST_COUNT, std::mem_fun_ref( &Cfoo::print ) );

             for_each( foo_, foo_+TEST_COUNT, boost::mem_fn( &Cfoo::print ) );

 

             Cfoo* pfoo[TEST_COUNT];

             forint i=0; i<TEST_COUNT; ++i )

             {

                           pfoo[i] = &foo_[i];

             }

             for_each( pfoo, pfoo+TEST_COUNT, std::mem_fun( &Cfoo::print ) );

             for_each( pfoo, pfoo+TEST_COUNT, boost::mem_fn( &Cfoo::print ) );

 

             for_each( pfoo, pfoo+TEST_COUNT, std::bind2nd( std::mem_fun1( &Cfoo::print_n ), 100 ) );

 

             // 위의 코드를 boost 로 바꾸면...

             for_each( pfoo, pfoo+TEST_COUNT, boost::bind( boost::mem_fn( &Cfoo::print_n ), _1, 100 ) );

             for_each( pfoo, pfoo+TEST_COUNT, boost::bind( &Cfoo::print_n, _1, 222 ) );

}

 

-----------------------------------------------------------------------------------------------------------------------------

 

위의 예제에서 배열을 알고리즘에서 적용하였는데요.

 

이는 포인터가 반복자중에 하나인 입력반복자의 필요충분조건을 모두 만족하다는 것입니다.

 

입력반복자가 되기 위한 조건은 아래와 같다.

 

1. 연산자 후방++, 전방++ 가 적용가능하고, 다음 입력반복자를 리턴해준다.

2. 연산자 !=, == 가 적용가능하고, 적절히 true, false 를 리턴해준다.

3. 연산자 * 가 적용가능하고, *it 는 it 가 가리키는 값을 리턴해준다.

4. 연산자 +,- 가 적용가능하고, 해당 입력반복자를 리턴해준다.

 

입력반복자는 한가지타입을 지칭하는 것이 아니라 위의 3가지 조건을 모두 만족하기만 하면, 그러한 타입을 입력반복자라고 한다.

 

아래의 예는 배열의 원소들을 sort 시키는 방법을 보여준다.

 

int nTest[5] = { 7, 10, 6, 1, 3 };
std::sort( nTest, nTest+5, std::less<int>() );
std::copy( nTest, nTest+5, std::ostream_iterator<int>( std::cout, "." ) );



 

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::function  (0) 2012.11.13
boost::unordered_set  (0) 2012.11.13
boost::bind  (0) 2012.11.13
boost::mem_fn  (0) 2012.11.13
boost::unordered_map  (0) 2012.11.13
반응형

http://cafe.naver.com/ecpp/176


#include <iostream>

#include "boost/bind.hpp"

 

void func(int a, int b, int c)

{

        std::cout << a << " " << b << " " << c << std::endl;

}

 

void main()

{

        boost::bind( &func, _3, _2, _1 )( 1, 2, 3 );

}






http://cafe.naver.com/ecpp/177



#include <iostream>

#include <string>

#include "boost/bind.hpp"

 

void printFunc(std::string s

{

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

}

 

class printClass

{

public:

        void print(std::string s)

        {

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

        }

};

 

void main()

{

        (boost::bind(&printFunc, _1))( " func " );

 

        (boost::bind(&printClass::print, printClass(), _1))( " member func " );

}











http://codevania.tistory.com/16




코드의 미묘한 중복을 줄이는데 템플릿만한 것이 없다고 생각한다.
보통 아래와 같은 패턴을 가진 함수들... 즉 Value와 Data의 타입이 다르지만 뭔가 동일한 루틴을 가진 함수들... 
이런 함수들이 여러개 있다면, 주저 없이 boost::bind를 사용해서 중복을 줄여보자.
( STL의 bind도 가능하지만, mem_fun에서 받을 수 있는 인자는 1개 뿐인 반면 boost는 8개다 )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool Func( ValueType Value, DataType Data )
{  
    // 뭔가를 검사하는 작업
    if ( 0 < Data.a )
    {
        ASSERT( "Someting bad is gonna happen. -_- [%d]", Data.a );
        return false;
    }
     
    // 여러 함수에 걸쳐... 약간씩 다른 함수 호출
    Value = Creator();
     
    // 여러 함수에 걸쳐... 동일한 루틴들
    ++m_iMyCount;
    DoSomething();
     
    return true;
}



Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
    DataType1 D1;
    DataType2 D2;
    int Sum = 0;   
 
    bool bSuccess = false;
    bSuccess = Func( Sum, D1, boost::bind( boost::mem_fn( &MyManager::Sum2 ), &g_Manager, D1.a, D1.b ) );
    ShowResult( bSuccess, Sum, "Sum2가 template이 아니라면 간단히 호출 가능" );
 
    bSuccess = Func( Sum, D1, boost::bind( boost::mem_fn< int, MyManager, int, short >( &MyManager::Sum2 ), boost::ref( g_Manager ), D1.a, D1.b ) );
    ShowResult( bSuccess, Sum, "Sum2가 template이라면 mem_fn을 명시적으로 호출" );
 
    boost::function< int( int, short ) > mfSum2 = boost::bind( &MyManager::Sum2, &g_Manager, _1, _2 );
    bSuccess = Func( Sum, D1, boost::bind( mfSum2, D1.a, D1.b ) );
    ShowResult( bSuccess, Sum, "mem_fn을 바인드 시켜서, 나중에 인자와 함께 호출" );
 
    boost::function< int() > FtrFunc = boost::bind( boost::mem_fn< int, MyManager, int, short >( &MyManager::Sum2 ), &g_Manager, D1.a, D1.b );
    bSuccess = Func( Sum, D1, FtrFunc );
    ShowResult( bSuccess, Sum, "함수 자체를 funtion에 바인드도 가능" );
 
    boost::function< int() > FtrFunc2 = boost::bind( boost::mem_fn< int, MyManager, int, short, long >( &MyManager::Sum3 ), &g_Manager, D2.a, D2.b, D2.c );
    bSuccess = Func( Sum, D1, FtrFunc2 );
    ShowResult( bSuccess, Sum, "인자3개짜리가 필요할 때도 간편하게 사용" );
}

결과 
(Result: 1 (Sum: 3 | Sum2가 template이 아니라면 간단히 호출 가능 
(Result: 1 (Sum: 3 | Sum2가 template이라면 mem_fn을 명시적으로 호출 
(Result: 1 (Sum: 3 | mem_fn을 바인드 시켜서, 나중에 인자와 함께 호출 
(Result: 1 (Sum: 3 | 함수 자체를 funtion에 바인드도 가능 
(Result: 1 (Sum: 6 | 인자3개짜리가 필요할 때도 간편하게 사용

반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::unordered_set  (0) 2012.11.13
Boost::[bind, mem_fn ] 과 STL , 멤버함수 조합사용  (0) 2012.11.13
boost::mem_fn  (0) 2012.11.13
boost::unordered_map  (0) 2012.11.13
boost::filesystem (파일, 디렉터리 다루기)  (0) 2012.11.04
반응형



http://jacking75.cafe24.com/Boost/bind/mem_fn_Sample.html


출처 : http://www.kmonos.net/alang/boost/classes/mem_fn.html

 

 

 

boost::mem_fn

abstract

필요한 헤더

<boost/mem_fn.hpp>

  있는 

멤버 함수를 보통 함수 같게 고치는

레퍼런스

en / jp

sample


#include <boost/mem_fn.hpp>

using namespace std;

struct SomeObject{

public:

       SomeObject( const char* i_name ) : name( i_name ) {}

       void Print() { cout << name << endl; }

private:

       const char* name;

};


int main(){

       vector<SomeObject> v;

       v.push_back(SomeObject("Taro"));

       v.push_back(SomeObject("Jiro"));

       v.push_back(SomeObject("Saburo"));

       v.push_back(SomeObject("Shiro"));

       v.push_back(SomeObject("Goro")); 


       // std::mem_fun_ref 의 대신

       for_each( v.begin(), v.end(), boost::mem_fn(&SomeObject::Print) );

       cout << "--------------" << endl;

       vector<SomeObject*> vp;

       vp.push_back(new SomeObject("Rokuro"));

       vp.push_back(new SomeObject("Shichiro"));

       vp.push_back(new SomeObject("Hachiro"));

       vp.push_back(new SomeObject("Kuro")); 


       // 완전히 같은 형태로

       // std::mem_fun 의 대신 으로도 사용할 수 있다.

       for_each( vp.begin(), vp.end(), boost::mem_fn(&SomeObject::Print) );

       // ToDo: delete...(^^;

       return 0;

}

출력예

Taro

Jiro

Saburo


etc

표준 라이브러리의 mem_fun 이용하면 ptr->Func() mem_fun(&Class::Func)( ptr )  고쳐  수가 있습니다 형태로  두면  for_each 등의 알고리즘을멤버 함수에 대해서도 이용할  있게 되어 편리합니다다만 이녀석은 obj.Func() 경우는 mem_fun_ref(&Class::Func)( obj )  다른 mem_fun_ref 되어 함수를 사용할 필요가 있거나 인수를 취하지 않는 함수 밖에 사용할  없기도 하고 실은 상당히 유연성이 부족합니다거기서boost::mem_fn.

mem_fn라고 하는 하나의 이름으로 포인터판과 참조판 const있음과 없음인수의 수는 2 이상에서도 OK 라고 폭넓게 서포트해 줍니다.

 

반응형
반응형


복사http://blog.naver.com/titetoto123/130139993684


★ unordered_map ★


해쉬 맵으로서 원소 타입은 value_type이다


 

#include <unordered_map>

 

 

int _tmain(int argc, _TCHAR* argv[])

{

        unordered_map<intint&> pGlobal;

        CSub2 pSub;

 

        pGlobal.insert(unordered_map<int,int&>::value_type(1,pSub.GetTest()));

 

        std::cout<<&pSub.GetTest()<<std::endl;

 

        unordered_map<intint&>::iterator iter;

        iter = pGlobal.find(1);

        std::cout<<&(iter->second)<<std::endl;

 

        return 0;

}

[출처] ★ unordered_map ★|작성자 titetoto123











http://cafe.naver.com/totalprogramming/88




boost에는 기존 C++ 표준 라이브러리에 없는 해쉬맵을 제공한다.

TR1에도 포함되어 있다. 앞으로 표준에 등록될 예정이다.

 

http://www.boost.org/doc/libs/1_36_0/doc/html/unordered.html

 

사용법은 기존 C++에서 map을 사용 하던 방식과 똑같고, c++의 맵과 다른점은

연산을 통해 상수시간에 검색한다는 것이다.

 

typedef boost::unordered_map<std::string, int> map;
map x;
x["one"] = 1;
x["two"] = 2;
x["three"] = 3;

assert(x.at("one") == 1);
assert(x.find("missing") == x.end());








이하는 Boost 와 TR1 성능비교이고 결론적으론 Boost 가 빠르다는 결론








http://cafe.naver.com/ongameserver/6797


각 각 100만개의 데이터를 토대로

Integer, string length = 10

 

키를 가지고 비교하였습니다별도의 키의 hash를 구현할 시 각각 틀릴 수 있으므로 integer std::string만 사용하였습니다.

 

[사양]

Inter Core i7-2600 CPU 3.40GHz

 

VS2008 SP1

 

[속도 체크]

Integer 개수 100만개 1~ 1000000

 

Insert

 

 

Find

 

 

Delete

 

 

 

Second

MilliSecond

Micro second

Second

MilliSecond

Micro second

Second

MilliSecond

microsecond

Std::map

0.197763

197.763189

197763.188756

0.000002

0.002113

2.112990

0.000005

0.005433

5.43340.

Std::tr1::unordered_map

0.124919

124.918763

124918.763080

0.000001

0.001207

1.207423

0.000002

0.001509

1.509279

Std::tr1::unordered_mapwith boost::fast_pool_allocator

0.0059479

59.478556

59478.556321

0.000001

0.001207

1.207423

0.000001

0.001207

1.207423

Boost::unordered_map

0.083059

83.058921

83058.921331

0.000000

0.000302

0.301856

0.000001

0.000906

0.905567

Boost::unordered_mapwith boost::fast_pool_allocator

0.086212

86.21248

86212.408021

0.000001

0.000604

0.603711

0.00000

0.00302

0.301856

 

 

문자열 개수 100만개 랜덤 (아스키 65 ~ 127) 조합 10글자

 

 

Insert

 

 

Find

 

 

Delete

 

 

 

Second

MilliSecond

Micro second

Second

MilliSecond

Micro second

Second

MilliSecond

microsecond

Std::map

0.978266

978.266388

978266.388275

0.000005

0.004528

4.152736

0.000005

0.005132

5.1315747

Std::tr1::unordered_map

0.451236

451.235661

451235.661476

0.000002

0.001811

1.811134

0.000002

0.001811

1.811134

Std::tr1::unordered_mapwith boost::fast_pool_allocator

0.481112

481.112133

481112.133060

0.000002

0.001509

1.509279

0.000002

0.001811

1.811134

Boost::unordered_map

0.498683

498.683154

498683.154428

0.000001

0.001207

1.207423

0.000002

0.001509

1.509279

Boost::unordered_mapwith boost::fast_pool_allocator

0.484535

484.535479

484535.478763

0.000001

0.00604

0.603711

0.000001

0.000604

0.603711

 

 

데이터가 100만개씩이라 디버깅으로는 안 돌렸습니다예전에 분석 결과로 기억나는 건 BOOST, TR1 둘다 디버깅 시에 검증 코드 엄청나서 느리다고 알고 있습니다. (안그래도 많은데…;;)



기존에 회사에서 저희팀에게 속도를 알리기 위하여 테스트 결과를 공유합니다. 


ATL은 빠져있습니다. 


결과는 좋은 색을 찾아 보시면 됩니다. 


현직에 계시는 분들 중에 boost라이브러리나 외부 라이브러리를 많이 사용하시는 편입니까?


(저희팀은 현재 외부라이브러리는 안쓰고 있습니다.)







http://blog.daum.net/naganolacpp/33




디버그 모드 10,0000번 루프

- TR1 -

삽입 2.187

검색 0.422

삭제 35.953

100,0000번 루프시 삭제 결과가 안나와 10,0000번으로 측정

- Boost -

삽입 3.328

검색 0.922

삭제 1.953

-------------------------------------------

릴리즈 모드 100,0000번 루프

- TR1 -

삽입 0.421

검색 0.11

삭제 0.547

- Boost -

삽입 0.281

검색 0.031

삭제 0.25

 

결론 : TR1보단 Boost

 

/**

*    test 소스 코드

*    shared_ptr도 살포시 돌려보았으나 별차이가 없었다.

*/

#include <unordered_map>
#include <memory>
#include <boost/unordered_map.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

#include <boost/timer.hpp>
#include <iostream>

template< typename T >
inline void Insert( T &map )
{
 boost::timer t;
 t.restart();
 for( size_t i = 0 ; i < 100000 ; ++i )
 {
  map.insert( std::pair<int,int>( i, i ) );  
 }
 std::cout << "삽입"<< t.elapsed() << std::endl;
};

template< typename T >
inline void Search( T &map )
{
 boost::timer t;
 t.restart();
 for( size_t i = 0 ; i < 100000; ++i )
 {
  map.find( i );
 }
 std::cout << "검색"<< t.elapsed() << std::endl;
};

template< typename T >
inline void Erase( T &map )
{
 boost::timer t;
 t.restart();
 for( size_t i = 0 ; i < 100000; ++i )
 {
  map.erase( i );
 }
 std::cout << "삭제"<< t.elapsed() << std::endl;
};

/*
template< typename T , typename Type >
inline void SharedCreate( std::vector<T> &list )
{
 list.resize(1000000);
 boost::timer t;
 t.restart();
 for( size_t i = 0 ; i < 1000000 ; ++i )
 {
  list[i] = T( new Type );
 }
 std::cout << "shard_ptr Create "<< t.elapsed() << std::endl;
}

class Test
{
public:
 void Run( void )
 {
  int a;
 }
};
template< typename T >
inline void SharedGetTest( std::vector<T> &list )
{
 boost::timer t;
 t.restart();
 size_t size = list.size();
 for( size_t i = 0 ; i < size; ++i )
 {
  list[i]->Run();
 }
 std::cout << "shard_ptr Run Test : "<< t.elapsed() << std::endl;
}
*/
void main()
{  
 std::tr1::unordered_map<int , int > tr1Map;
 std::cout << "- TR1 -\n";
 Insert( tr1Map );
 Search( tr1Map );
 Erase( tr1Map );

 boost::unordered_map<int , int > boostMap;
 std::cout << "- Boost -\n";
 Insert( boostMap );
 Search( boostMap );
 Erase( boostMap );
/*
 std::cout << "- Boost -\n";
 std::vector< boost::shared_ptr<Test> > boostShared;
 boostShared.resize(1000000);
 SharedCreate< boost::shared_ptr<Test>, Test >( boostShared );
 SharedGetTest( boostShared );

 std::cout << "- TR1 -\n";
 std::vector< std::tr1::shared_ptr<Test> > tr1Shared;
 tr1Shared.resize(1000000);
 SharedCreate<  std::tr1::shared_ptr<Test>, Test >( tr1Shared );
 SharedGetTest( tr1Shared );
 */
}









http://npteam.net/779


Map Container Iterating

이번엔 Map Container Iterating에 대해서 측정해 보았다.

지난번 블로깅에서 Functor가 가장 빠른 Iterating 속도를 보여줬으므로,
모든 Map Container에 대해서 Functor Iterating을 이용하여 측정하였다.

측정 환경 : Visual Studio 2008
측정 컨테이너 :
    1. std::map
    2. stdext::hash_map
    3. boost::unordered_map
측정 방법 : Functor

std::map과 boost::unordered_map은 약 2:1의 측정 속도 차이를 보여준다.
map data의 순서 정렬 보장이 필요없는 경우에는 boost::unordered_map을 사용하는 것이 더 빠른 속도를 얻을 수 있다.
map container의 경우에는 균형 탐색 트리(balanced search tree)로 구현되어 있기 때문에, 로그(Log) 시간 복잡도를 보장한다.
unordered_map은 Hash 알고리즘으로 Bucket을 찾아가기 때문에 검색속도가 빠르고 향상된 검색 속도만큼 Iterating 시간이 짧이졌다.
그에 비해 hash_map의 경우에는 초기에 STL에 포함되지 않아서 각 컴파일러 제작 회사마다 각각 구현하여 포함되었으므로, Hash 알고리즘이 최적화되어 있지 않아서 Iterating 및 검색속도가 떨어지는 문제점이 있다.




반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::bind  (0) 2012.11.13
boost::mem_fn  (0) 2012.11.13
boost::filesystem (파일, 디렉터리 다루기)  (0) 2012.11.04
boost::chrono, std::chrono [시간 측정하기]  (0) 2012.11.03
Chapter 6. Boost.Container - 번역중  (0) 2012.10.27
반응형


블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..

by 송정헌




퍼온 글에는 cout << it->leaf() << endl;  으로 작성되어있지만 boost 1.50 버전에서는 이때 컴파일 버그가 난다

cout << it->path().leaf() << endl; 으로 하면 제대로 나오는것을 알 수 있다
(하지만 정확히 허용되는 버전 범위는 확인하지않음)



The expression itr->path().leaf() == file_name, in the line commented // see below, calls the leaf() function on the path returned by calling the path() function of the directory_entry object pointed to by the iterator. leaf() returns a string which is a copy of the last (closest to the leaf, farthest from the root) file or directory name in the path object.





 
또한 boost 의

class directory_iterator
    : public boost::iterator_facade< directory_iterator,
                                     directory_entry,
                                     boost::single_pass_traversal_tag >


클래스 내용을 보면 directory_iterator 생성자가

directory_iterator(){}  // creates the "end" iterator

를 만든다는 내용또한 나와있다 그래서 directory_iterator end; 라고 쓴다







http://cafe.naver.com/javacircle/46010




헤더
<boost/filesystem/path.hpp>, (패스 문자열)
<boost/filesystem/operations.hpp>, (파일 조작)
<boost/filesystem/fstream.hpp>, (파일 입출력)
<boost/filesystem/exception.hpp>, (예외)
<boost/filesystem/convenience.hpp>, (편리 함수 여러가지)

기능
파일·디렉토리 조작

#include <iostream>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace std;

int main()
{
  namespace fs = boost::filesystem;

  // 디렉토리 작성
  fs::path dir( "my_dir" );
  fs::create_directory( dir );

  // 파일을 열어 기입―
  // 디렉토리명과 파일명의 결합은 / 연산자로
  fs::ofstream f( dir/"test.txt" );
  f << "Hello!" << endl;
  f.close();

  // 커런트 디렉토리의 파일 일람 해 보자
  fs::directory_iterator end;
  for( fs::directory_iterator it(fs::current_path()); it!=end; ++it )
  {
    if( fs::is_directory(*it) )
      cout << "D ";
    else
      cout << "F ";
    // leaf() 패스 정보를 자르고, 파일의 이름 부분만 꺼내
    cout << it->path().leaf() << endl;
  }

  return 0;
}

C/C++표준 라이브러리에는, 「파일을 삭제한다」「디렉토리를 작성한다」라고 하는 함수가 존재하지 않습니다. 역사적인 경위는 전혀 모릅니다만, OS마다 디렉토리 단락의 기호가 \ 이거나 : 이거나 / 이거나와 가지각색인 일이나, 원래 디렉토리라고 하는 개념이 없는 환경도 있거나 하기 때문입니다. C++에서는 파일 그 자체를 조작 하려고 하면, CreateDirectory라든가 mkdir나 DeleteFile, unlink, 등의 OS 특유의 기능을 이용할 필요가 있습니다.

 이들을 래핑 한 라이브러리( ACE 의 일부나 sord 등)가 등장했습니다. boost::filesystem 도 그 하나입니다. 

또,directory_iterator에 의한 디렉토리를 읽거나, 기본적으로 std::fstream 와 같은 fs::fstream 에 의한 파일의 읽고 쓰기도, 라이브러리의 일부로서 포함되어 있습니다.




http://cafe.naver.com/javacircle/12469



디렉터리를 생성, 삭제 또는 파일을 이동하는 작업을 어떠한 개발 환경에서도 동일한 코드로 작성할수 있게 한다는 취지에서 시작한게 바로 boost의 FileSystem 라이브러리 입니다.

 

#include <iostream>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
using namespace std;
using namespace boost::filesystem;

int main()
{
    // 디렉터리 "backup"을 작성
    path backup_dir( "backup" );
    create_directory( backup_dir );

    // "readme.txt"가 존재하면, "backup/readme.bak"에 복사
    path work_file( "readme.txt" );
    if( exists(work_file) )
        copy_file( work_file, backup_dir / "readme.bak" );

    
    // "backup" 디렉터리안의 내용(파일/디렉터리)를 삭제
    remove_all( backup_dir );
    return 0;





http://cobaltic5.tistory.com/63


.목적 : filesystem 관련 기능 제공( 파일 생성/삭제 , path 관리)

.생성
  • 생성자에 경로를 인자로 넣음, unix, window 방식 모두 지원
. query
  • .filename() - 파일명을 리턴함.
  • .extension() - 확장자를 리턴함.
  • .is_complete() - full path 인지 relative path 인지 알려줌.
. path concatenate
  • / operator 이용
  • path("c:\\ss\\test"); path2("../test.h");
  • path3 = path/path2;
  • path3.string() -> c:/ss/test/../test.h 리턴
  • path3.normalize() -> c:/ss/test.h 리턴
. link
  • libboost-filesystem , libbost-system 필요
. reference




반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::mem_fn  (0) 2012.11.13
boost::unordered_map  (0) 2012.11.13
boost::chrono, std::chrono [시간 측정하기]  (0) 2012.11.03
Chapter 6. Boost.Container - 번역중  (0) 2012.10.27
Chapter 2. Boost.Any  (0) 2012.10.27
반응형


boost 에도 chrono 가 있다

거의 동일하다봐도됨



http://jacking.tistory.com/988



[ VC11-C++11 ] chrono - 시간 측정하기

chrono는 C++11에서 새로 추가된 시간 라이브러리입니다기존의 C 런타임에서 제공하는 time 함수에 비해서 다양한 기능이 있고사용이 쉽고 정밀도는 훨씬 높습니다. time 함수는 초 단위의 값만 측정할 수 있는 것에 비해 chrono는 나노 밀리 초 단위도 측정할 수 있습니다.

 

현재의 C++(C++03)에서는 초 단위보다 더 정밀한 단위로 시간을 측정할 때는 OS에서 제공하는 API를 사용해야 했는데 chrono를 사용하면 OS 독립적으로 높은 단위의 시간을 측정할 수 있습니다.

 

VC10에서는 chrono가 들어가지 않았지만 이번 VC11에서 chrono STL에 들어갔습니다만약 VC11을 사용하지 못하는 경우라면 Boost 라이브러리를 사용하면 사용할 수 있습니다.

 

chrono를 사용하면 특정 시간 구간에 걸린 시간을 초밀리 초나노 초 단위로 얻을 수 있으며 또 시간끼리 연산을 할 수 있습니다

 

 

 

chrono 사용 방법

 

chrono를 사용하기 위해서는 아래의 헤더 파일을 추가합니다.

#include <chrono>

 

 

chrono에 대한 자세한 설명에 앞서 어떤 기능인지 좀 더 쉽게 알 수 있도록 예제를 하나 보여드리겠습니다아래의 예제는 어떤 함수의 성능을 측정하기 위해서 chrono를 사용했습니다.

 

 

예제. 1 >

#include <chrono>

#include <iostream>

#include <cmath>

 

 

void Test()

{

           for ( long i = 0; i < 10000000; ++i )

           {

                     std::sqrt( 123.456L );

           }

}

 

 

 

int main()

{

 

    std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

 

    Test();

          

    std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;

 

    std::cout << "Test() 함수를 수행하는 걸린 시간() : " << sec.count() << " seconds" << std::endl;

 

    return 0;

}

 

실행 결과 >

 


<예제.1>에서는 std::chrono::system_clock::now()을 사용하여 현재 시간을 얻습니다.

 std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

여기서 time_point 타입은 시간 상의 한 축을 뜻합니다.

 

 

 

이후 Test() 함수를 실행한 후 다시 현재 시간을 얻은 후 Test()를 시작하기 전에 저장한 현지 시간을 빼면 Test()를 수행하는 걸린 시간을 얻을 수 있습니다.

 

std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;

 

 

* std::chrono::system_clock::now()에 의해서 얻는 시간의 초기 시간은 1970년 입니다.

 

 


 

시간 단위

chrono는 경과 시간을 계산할 때 다양한 시간 타입으로 계산할 수 있습니다.

 

<예제.1>에서는 초 단위의 정밀도로 소수점까지 표시할 수 있었습니다.

 

std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;

 

그런데 보통은 소수점이 나오는 결과 값보다는 정수로 나오는 값을 사용하는 경우가 많을 것입니다.

 

 

chrono에서는 경과 시간을 나타내는 클래스는 duration입니다.

duration 6개의 시간 단위를 지원합니다.

 

std::chrono::nanoseconds  // 나노 세컨드. 10억분의 1

std::chrono::microseconds // 마이크로 세컨드. 100만분의 1

std::chrono::milliseconds   // 밀리 세컨드. 1000분의 1

std::chrono::seconds        // 

std::chrono::minutes         // 

std::chrono::hours            // 

 

<예제.1>을 수정하여 위에 열거한 chrono의 다양한 단위를 사용하여 시간 측정을 해 보겠습니다.

 

예제. 2 >

#include <chrono>

#include <iostream>

#include <cmath>

 

 

void Test()

{

           for ( long i = 0; i < 10000000; ++i )

           {

                     std::sqrt( 123.456L );

           }

}

 

int main()

{

    std::chrono::system_clock::time_point StartTime = std::chrono::system_clock::now();

          

    Test();

 

    std::chrono::system_clock::time_point EndTime = std::chrono::system_clock::now();

 

 

 

    std::chrono::duration<double> DefaultSec = EndTime - StartTime;

 

    std::chrono::nanoseconds nano = EndTime - StartTime;

 

    std::chrono::microseconds micro = std::chrono::duration_cast<std::chrono::microseconds>(EndTime - StartTime);

 

    std::chrono::milliseconds mill  = std::chrono::duration_cast<std::chrono::milliseconds>(EndTime - StartTime);

 

    std::chrono::seconds sec = std::chrono::duration_cast<std::chrono::seconds>(EndTime - StartTime);

 

    std::chrono::minutes min = std::chrono::duration_cast<std::chrono::minutes>(EndTime - StartTime);

 

    std::chrono::hours hour = std::chrono::duration_cast<std::chrono::hours>(EndTime - StartTime);

  

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << DefaultSec.count() << " default" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << nano.count() << " nanoseconds" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << micro.count() << " microseconds" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << mill.count() << " milliseconds" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << sec.count() << " seconds" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << min.count() << " minutes" << std::endl;

    std::cout << "Test() 함수를 수행하는 걸린 시간 : " << hour.count() << " hour" << std::endl;

          

    return 0;

}

 

실행 결과 >









http://sweeper.egloos.com/2996847






1. 지금까지의 시간 계측 방법들

프로젝트를 진행하다 보면, 이래저래 특정 이벤트가 수행된 시간을 계측해야 되는 경우가 꽤 된다.

이럴 때 아주 높은 정밀도가 필요치 않다면, mill-second까지 뽑아줄 수 있는 아래 함수들을 사용한다.
  • GetTickCount
  • timeGetTime : 멀티미디어 라이브러리를 이용 (Windows.h와 winmm.lib 필요)
GetTickCount의 경우 시스템 타이머 정밀도의 영향을 받아, 최소 정밀도가 10~16ms 정도 된다.

이보다 조금 더 정밀도가 높은 timeGetTime의 경우, 멀티미디어 타이머에 영향을 받으며,
보통 5ms 이상이라고 한다. (머신에 따라 다르다고 한다)

timeGetTime의 경우, 정확한 정밀도를 갖게 하려면 다음과 같이 타이머 정밀도를 끌어 올릴 수 있다.

  1. #include <Windows.h>
  2. #pragma comment(lib, "winmm.lib")
  3.  
  4.  
  5. timeBeginPeriod(1);
  6.  
  7. // ...timeGetTime 사용
  8.  
  9. // timeEndPeriod의 인자값은 timeBeginPeriod에서 설정한 인자값과 동일해야 한다
  10. timeEndPeriod(1);

Milli-second보다 더 높은 정밀도의 계측 도구가 필요한 경우 유일한 대안은 
QueryPerformanceQuery / QueryPerformanceCounter 였다.

하지만, 이는 OS가 제공하는 기능이었지, C++의 표준 메써드는 아니었다.

이와 관련된 자세한 내용은 예전에 정리해 둔 문서로 대체한다.

즉, 지금껏 C++ 표준의 고정밀 시간 계측 도구가 없었던 셈이다.


2. boost::chrono의 등장

boost 1.47.0(2011년 7월에 발표)에 Vicente J. Botet Escribá 라는 사람에 의해 처음으로 boost::chrono가 도입된다.
(이 히스토리는 http://www.boost.org/doc/libs/ 에서 확인 가능하다)

자세한 내용은 boost::chrono 페이지에서 확인이 가능하다.

참고로, 문서의 내용은 boost의 것이 MSDN 것보다 훨씬 자세하므로, 
개별 클래스나 구조체에 대한 내용은 boost의 것을 보는 게 더 나을 수도 있다.


3. C++11 표준의 chrono

C++11에서 드디어 chrono가 표준으로 채택되었고, VS2012에도 포함이 되어 있다.
(boost::chrono의 주요 특징을 거의 채택하였으나, VS2012의 chrono는 clock class가 boost::chrono와 조금 다르다)

VS2012의 chrono에 대한 설명은 MSDN 링크 페이지에서 확인할 수 있다.

chrono는 요약해 정리하면,
기존 C/C++ 런타임의 time 함수에 비해 많은 기능을 가지고 있으며, 훨씬 더 정밀하고 훨씬 더 편하게 사용할 수 있다.

정밀도는 nano-second까지 지원하며, 시간 단위의 값끼리 연산도 가능하다.

또한, 기존의 C/C++ 런타임의 time 체계와도 어느 정도 호환이 가능하다.


4. 기본 사용법

chrono를 사용하기 위해선 <chrono> 헤더 파일이 필요하며, 아래와 같은 namespace에 속한다.

  1. #include <chrono>
  2.  
  3. /-
  4. namespace std
  5. {
  6.     namespace chrono
  7.     {
  8.     }
  9. }
  10. *-
  11.  
  12. // 즉, 주로 사용시엔 아래와 같이 using namespace를 쓰는 게 편하다.
  13. using namespace std;
  14. using namespace chrono;

우선, 간단한 예제를 통해 가장 기초적인 사용법을 익혀보자.

  1. #include <chrono>
  2.  
  3. using namespace std;
  4. using namespace chrono;
  5.  
  6. // Debug 모드로 재 보니, i5-750에서 9.87초나 걸린다
  7. void BigLoop()
  8. {
  9.     for (int i = 1; i <= 50000; i++)
  10.     {
  11.         for (int j = 1; j <= 50000; j++)
  12.         {
  13.             int x = (+ j) * 2 + (/ j);
  14.         }
  15.     }
  16. }
  17.  
  18. int main()
  19. {
  20.     // now() 함수를 통해 현재 시간값을 구한다.
  21.     system_clock::time_point start = system_clock::now();
  22.  
  23.     BigLoop();
  24.  
  25.     system_clock::time_point end = system_clock::now();
  26.  
  27.     // 초 단위 (소수점으로 표현)
  28.     duration<double> sec = end - start;
  29. }

chrono에서 시간을 구하는 함수는 now() 함수이며, 원형은 아래와 같이 작성되어 있다.

  1. static time_point now() _NOEXCEPT
  2. {
  3.     // get current time
  4.     return (time_point(duration(_Xtime_get_ticks())));
  5. }

정적 함수로 정의되어 있으며, time_point 객체를 반환한다.

time_point 클래스는 시간을 나타내는 하나의 포인트를 의미하며,
now() 함수를 통해 찍어놓는 하나의 타임 마크라고 생각하면 된다.

참고로, time_point 클래스는 아래와 같이 정의되어 있다.

  1. template<class _Clock, class _Duration = typename _Clock::duration>
  2. class time_point
  3. {       // represents a point in time
  4. public:
  5.     typedef _Clock clock;
  6.     typedef _Duration duration;
  7.     typedef typename _Duration::rep rep;
  8.     typedef typename _Duration::period period;
  9.  
  10.     time_point() : _MyDur(_Duration::zero())
  11.     {   // check asserts
  12.         static_assert(_Is_duration<_Duration>::value,
  13.                         "duration must be an instance of std::duration");
  14.     }
  15.  
  16.     explicit time_point(const _Duration& _Other) : _MyDur(_Other)
  17.     {   // construct from a duration
  18.     }
  19.  
  20.     template<class _Duration2>
  21.     time_point(const time_point<_Clock, _Duration2>& _Tp,
  22.                typename enable_if<is_convertible<_Duration2, _Duration>::valuevoid>::type ** = 0)
  23.         : _MyDur(_Tp.time_since_epoch())
  24.     {   // construct from another duration
  25.     }
  26.  
  27.     _Duration time_since_epoch() const
  28.     {   // get duration from epoch
  29.         return (_MyDur);
  30.     }
  31.  
  32.     time_point& operator+=(const _Duration& _Dur)
  33.     {   // increment by duration
  34.         _MyDur += _Dur;
  35.         return (*this);
  36.     }
  37.  
  38.     time_point& operator-=(const _Duration& _Dur)
  39.     {   // decrement by duration
  40.         _MyDur -= _Dur;
  41.         return (*this);
  42.     }
  43.  
  44.     static time_point (min)()
  45.     {   // get minimum time point
  46.         return (time_point((_Duration::min)()));
  47.     }
  48.        
  49.     static time_point (max)()
  50.     {   // get maximum time point
  51.         return (time_point((_Duration::max)()));
  52.     }
  53.  
  54. private:
  55.     _Duration _MyDur;   // duration since the epoch
  56. };

템플릿 인자로 Duration을 가지는데, Duration은 chrono에서 경과 시간을 나타내는 클래스로써 역할을 한다.

Duration에 대해선 아래에 자세히 설명하곘다.


5. chrono의 시간 단위

chrono는 duration 클래스의 typedef 형태로 6개의 기본 시간 단위를 제공된다. 

이는 유저가 필요시 또 다른 typedef를 사용할 수 있음을 의미한다.

  1. typedef duration<int, ratio<3600> > hours;
  2. typedef duration<int, ratio<60> > minutes;
  3.  
  4. typedef duration<long long> seconds;
  5.  
  6. typedef duration<long long, milli> milliseconds;
  7. typedef duration<long long, micro> microseconds;
  8. typedef duration<long long, nano> nanoseconds;

이를 통해 위 예제를 다양한 시간 단위로 표현할 수 있다.

  1. system_clock::time_point start = system_clock::now();
  2.  
  3. BigLoop();
  4.  
  5. system_clock::time_point end = system_clock::now();
  6.  
  7. // 시간 단위
  8. hours hour = duration_cast<hours>(end - start);
  9. // 분 단위
  10. minutes min = duration_cast<minutes>(end - start);
  11. // 초 단위
  12. duration<double> sec = end - start;
  13. // 밀리 초 단위 (1/1000)
  14. milliseconds milliSec = duration_cast<milliseconds>(end - start);
  15. // 마이크로 초 단위 (1/1000000)
  16. microseconds microSec = duration_cast<microseconds>(end - start);
  17. // 나노 초 단위 (1/1000000000)
  18. nanoseconds nanoSec = end - start;

나노 초 단위가 아닌 시간 단위로 표현할 때엔, 
위와 같이 duration_cast를 사용하여 명시적 캐스팅을 해 주어야 한다.

이는 now() 함수가 반환하는 기본 단위가 정밀도가 가장 높은 nano seconds 단위임을 의미한다.

또한, 위에서 6개의 시간 단위는 duration 클래스의 typedef라고 얘기하였다.
이는 milli second로 표현할 때에도 소수점 표현이 가능하다는 이야기이다.

즉, 아래와 같이 자신만의 typedef를 통해 소수점으로 표현이 가능한 milli-second 단위를 사용할 수 있다.

  1. // 밀리 초 단위를 double로 표현하고 싶다.
  2. typedef duration<double, milli> doublemillisec;
  3.  
  4. doublemillisec doubleMilliSec = duration_cast<doublemillisec>(end - start);

이쯤 되면, duration 클래스가 어찌 생겨먹었는지 궁금해 진다.
아래 코드를 살펴보자.

  1. // _Rep : 표현하고자 하는 단위의 타입 (즉, long, double)
  2. // _Period : 시간 단위를 얼마의 비율로 보여 줄것인가? (1/1000인가? milli, 1/1000000인가? micro)
  3. template<class _Rep, class _Period>
  4. class duration
  5. {    // represents a time duration
  6.  
  7.     // ...
  8.  
  9.     // 기본 사칙 연산과 % 연산자를 지원한다.
  10. };

위에서 보듯이 duration 클래스의 인자를 통해 초(second) 대비 시간의 비율 값을 특정 타입으로 표현함을 지정할 수 있다.
따라서, 기본 6개의 단위 외 얼마든지 원하는 형태로 시간 단위를 정의할 수 있다.

참고로, chrono의 milli, nano 등은 ratio 클래스를 typedef 한 것이다.
ratio 클래스까지 모조리 설명하면, 너무 멀리 나가게 되므로, 아래 typedef만 살펴 보자.

  1. typedef ratio<1(_LONGLONG)1000000000 * 1000000000> atto;
  2. typedef ratio<1(_LONGLONG)1000000 * 1000000000> femto;
  3. typedef ratio<1(_LONGLONG)1000 * 1000000000> pico;
  4. typedef ratio<11000000000> nano;
  5. typedef ratio<11000000> micro;
  6. typedef ratio<11000> milli;
  7. typedef ratio<1100> centi;
  8. typedef ratio<110> deci;
  9. typedef ratio<101> deca;
  10. typedef ratio<1001> hecto;
  11. typedef ratio<10001> kilo;
  12. typedef ratio<10000001> mega;
  13. typedef ratio<10000000001> giga;
  14. typedef ratio<(_LONGLONG)1000 * 10000000001> tera;
  15. typedef ratio<(_LONGLONG)1000000 * 10000000001> peta;
  16. typedef ratio<(_LONGLONG)1000000000 * 10000000001> exa;


6. 다양한 clock 클래스

boost::chrono와 VS2012 chrono가 clock 클래스에서 조금 다른 부분이 있다고 하였다.

우선, boost::chrono의 clock 클래스로는 아래 것들이 있다.
  • system_clock
  • steady_clock
  • high_resolution_clock
  • process_real_cpu_clock
  • process_user_cpu_clock
  • process_system_cpu_clock
  • process_cpu_clock
  • thread_clock
헌데, VS2012 chrono에는 딱 세 가지 clock 클래스만 포함되어 있다.
  • system_clock
  • steady_clock
  • high_resolution_clock
지금부터는 VS2012의 chrono를 기준으로 각 클래스의 성격에 대해 설명하겠다.

1. system_clock

가장 일반적인(특수성이 없는) clock 클래스라고 볼 수 있다.

위에서 chrono를 설명할 때, time 함수들과 호환성이 있다고 하였는데, 
아래 두 가지 함수를 통해 호환 기능을 제공하고 있다.

  1. // time_point -> time_t
  2. system_clock::time_point currTimePoint = system_clock::now();
  3. time_t currTime = system_clock::to_time_t(currTimePoint);
  4.  
  5. // time_t -> time_point
  6. time_t currTime = time(nullptr);
  7. system_clock::time_point currTimePoint = system_clock::from_time_t(currTime);

2. steady_clock

steady_clock은 system_clock을 상속받으며, 딱 2개의 정적 변수만을 추가로 가지고 있다.

또한, steady_clock은 monotonic_clock이라는 별칭을 가지고 있다.
(monotonic은 "증가 또는 감소만 하는" 이라는 사전적 의미를 가지고 있다)

  1. class steady_clock : public system_clock
  2. {    // wraps monotonic clock
  3. public:
  4.     static const bool is_monotonic = true;      // retained
  5.     static const bool is_steady = true;
  6. };
  7.  
  8. typedef steady_clock monotonic_clock;   // retained

원래 steady(monotonic)_clock은 사전적 의미처럼, 절대로 역행하지 않는 개념의 clock 클래스이다.

steady_clock 이외의 clock 클래스는 time_point를 얻은 후 
운영체제의 시간을 뒤로 돌린 후 time_point을 얻으면 시간이 과거의 값으로 구해진다.

하지만, steady_clock에서는 이것이 통하지 않는다.
따라서, 시간의 값이 시스템 설정과 무관하게 한결같이 흘러가야 할 때엔 steady_clock을 사용하는 것이 좋다.

문제는 현재 VS2012의 chrono 구현에서는 is_monotonic이든, is_steady이든 변수를 사용하는 곳이 없다.
(주석의 retained 즉, 보류되었음을 통해서도 알 수 있다)

혹시나 하고 테스트를 해 보았지만, 아쉽게도 steady_clock을 쓰고 날짜를 바꾼 뒤 다시 재 보았지만, 시간이 역행했다.
즉, 아직 VS2012에는 steady_clock 기능이 제대로 구현되어 있지 않은 것이다.

3. high_resolution_clock

그리고, high_resolution_clock은 system_clock의 typedef일 뿐이다.

typedef system_clock high_resolution_clock;


총 정리해보면, 아직 VS2012의 실질적 clock 클래스는 system_clock 하나인 셈이다.


7. chrono vs QueryPerformanceCounter 성능

음... 뭐만 나왔다 하면, 쓰윽 써보고 성능을 재보는 게 몸에 베서리...
이번에도 chrono의 now() 함수와 QueryPerformanceCounter() 함수의 성능을 비교해 보았다.

실험에 사용된 머신의 개략적 스펙은 다음과 같다.
  • CPU : i5-750 no overclock
  • RAM : 4GB
테스트 코드

  1. #include <Windows.h>
  2. #include <iostream>
  3. #include <chrono>
  4.  
  5. using namespace std;
  6. using namespace chrono;
  7.  
  8. void ChronoLoop()
  9. {
  10.     system_clock::time_point start;
  11.  
  12.     for (int i = 1; i <= 10000; i++)
  13.     {
  14.         for (int j = 1; j <= 10000; j++)
  15.         {
  16.             start = system_clock::now();
  17.         }
  18.     }
  19. }
  20.  
  21. void QueryLoop()
  22. {
  23.     LARGE_INTEGER li;
  24.     for (int i = 1; i <= 10000; i++)
  25.     {
  26.         for (int j = 1; j <= 10000; j++)
  27.         {
  28.             QueryPerformanceCounter(&li);
  29.         }
  30.     }
  31. }
  32.  
  33. typedef duration<double, milli> doublemillisec;
  34.  
  35. int main()
  36. {
  37.     system_clock::time_point start = system_clock::now();
  38.     ChronoLoop();
  39.     system_clock::time_point end = system_clock::now();
  40.  
  41.     doublemillisec doubleMilliSec = duration_cast<doublemillisec>(end - start);
  42.     cout << "ChronoLoop: " << doubleMilliSec.count() << endl;
  43.  
  44.     start = system_clock::now();
  45.     QueryLoop();
  46.     end = system_clock::now();
  47.  
  48.     doubleMilliSec = duration_cast<doublemillisec>(end - start);
  49.     cout << "QueryLoop: " << doubleMilliSec.count() << endl;
  50.  
  51.     return 0;
  52. }

테스트 결과

<Debug>
ChronoLoop: 10046.4 ms
QueryLoop: 1544.4 ms

<Release>
ChronoLoop: 951.6 ms
QueryLoop: 1357.2 ms

디버그에서는 심하게 느리지만, 릴리즈 모드에서는 Chrono가 약 30% 정도 빠름을 알 수 있다.

출처:[C++11] chrono


반응형

'메타프로그래밍 > Boost::' 카테고리의 다른 글

boost::unordered_map  (0) 2012.11.13
boost::filesystem (파일, 디렉터리 다루기)  (0) 2012.11.04
Chapter 6. Boost.Container - 번역중  (0) 2012.10.27
Chapter 2. Boost.Any  (0) 2012.10.27
Chapter 1. Boost.Accumulators  (0) 2012.10.27
반응형

Ion Gaztanaga

the Boost Software 라이센스 하에 배포되어졌다, Version 1.0.

(첨부된 파일을 보세요 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

Boost.Container 라이브러리는 STL 컨테이너를 포함하면서, 몇몇의 잘알려진 컨테이너들을 수행한다.

라이브러리의 목적이 향상된 특징들을 제공하기위해서 표준안에서 존재하지않거나 또는 최신표준을 제공하기위해서 C++03 을 따르는 컴파일러들에 기초된 특징들이다.

간단히 말해서 , Boost.Container 가 무엇을 제공하는가?

  • 이동의미(론)가 수행되어진다, pre-C++11 컴파일러들에 대한 에뮬레이션을 포함하면서...
  • 새로운 향상된 특징기능들이 존재한다 ( 예를들어 배치삽입(placement insertion), 재귀적 컨테이너들) .
  • 컨테이너들은 stateful 할당기들을 제공하고 Boost.Interprocess(그것들은 공유의 메모리안에서 안전하게 위치되어질수 있다)
    함께 호환된다.
  • 라이브러리들은 새로운 유용한 컨테이너들을 제공한다:
    • flat_map, flat_set, flat_multiset 그리고 flat_multiset: 표준 연관 컨테이너들을 위한 예약없는 교체 그러나
      더 사용하기쉬운 메모리 그리고 더빠른 검색.
    • stable_vector:
      std::list 와 std::vector hybrid 컨테이너:
      vector같은 임의접근 iterators 와 삽입들과 삭제들에서 리스트같은 iterator 안전성.
    • slist: 상수시간 size()을 제공하던 예전의 이전표준 싱글링크드리스트 구현.
      주의 : C++11의 forward_list 은 어떤 size()도 가지지않는다.

Boost.Container를 빌드하는것

Boost.Container를 컴파일할 필요는없다, 그것은 오직 헤더라이브러리이기 때문에.

단지 당신의 컴파일러 include 경로에 당신의 Boost 헤어 디렉토리를 포함시켜라.

Boost.Container는 적절한 C++98 호환성을 필요로한다. 작동하기위한 알려진 몇몇의 컴파일러들이 존재한다 :

  • Visual C++ >= 7.1.
  • GCC >= 4.1.
  • Intel C++ >= 9.0

Last revised: August 15, 2012 at 23:43:58 GMT


효율적인 삽입

이동의미(론)와 배치삽입은 당신의 C++ 어플리케이션들안에서 매우 긍정적인 영향을 가질수 있는 C++1 컨테이너들에의해 제공되어진 두가지 특징들이다. Boost.컨테이너들은 C++과 c++03 컴파일러들 모두를 위해서 두가지의 기술들을 이행한다

Move-aware 컨테이너들

모든 컨테이너들은 이동만가능한 유일한 타입들을 저장할수있는 Boost.컨테이너에 의해서 제공되어지고 value_type을 위한 요구조건들은

각 컨테이너 연산들에 의존한다.

C++3 컴파일러들에서 조차 C++11 필요조건들을 따르면서, 많은 연산들은 단지 복사 생성할수있는 타입들 대신에 이동할수있거나

기본(default) 생성할수있는 타입들을 지금부터 필요로한다.

컨테이너 그것들자체는 또한 이동할수있다, 예외를던지지 않는 보장과함께 만약 allocator나 predicate(있을경우) 복사연산들은 예외를

던지지않는다면..

이것은 고성능 연산들을 가능하게한다 데이터를 벡터들사이에서 옮길때.

예제를 봅시다 :

#include <boost/container/vector.hpp>
#include <boost/move/move.hpp>
#include <cassert>

//Non-copyable 클래스
class non_copyable
{
   BOOST_MOVABLE_BUT_NOT_COPYABLE(non_copyable)

   public:
   non_copyable(){}
   non_copyable(BOOST_RV_REF(non_copyable)) {}
   non_copyable& operator=(BOOST_RV_REF(non_copyable)) { return *this; }
};

int main ()
{
   using namespace boost::container;

   //벡터안에서 noe-copyable 오브젝트들을 저장한다
vector<non_copyable> v; non_copyable nc; v.push_back(boost::move(nc)); assert(v.size() == 1); //Reserve는 복사생성할수있는것을 더이상 필요로하지 않는다 v.reserve(100); assert(v.capacity() >= 100); //이 resize 오버로드는 이동하거나 기본 생성할수있는것을 단지 필요로한다 v.resize(200); assert(v.size() == 200); //컨테이너들은 또한 이동할수있다 vector<non_copyable> v_other(boost::move(v)); assert(v_other.size() == 200); assert(v.empty()); return 0; }

Emplace: 배치 삽입

Boost.Container에 의해 제공되어진 모든 컨테이너들은 배치삽입을 수행한다, 그것은(배치삽입) 오브젝트들이 어떤 임시오브젝트를 생성하는것 없이 사용자 아규먼트들로부터 직접적으로 컨테이너로 만들 수 있다는것을 의미한다.

컴파일러들을 위해 variadic template들없이 배치삽입이 아규먼트들의 한정된 (10)번까지 애뮬레이트되어지도록 지원하시오.

이동하는 값비싼 타입들은 완벽한 후보자들이다

emplace 함수들과 노드컨테이너들(list, set, ...) emplace 의 경우에는 컨테이너들 안에서 이동할수없고 복사할수없는 타입들을

정렬하는것을 허락한다 :

#include <boost/container/list.hpp>
#include <cassert>

//복사할 수 없고 이동할수없는 클래스
class non_copy_movable
{
   non_copy_movable(const non_copy_movable &);
   non_copy_movable& operator=(const non_copy_movable &);

   public:
   non_copy_movable(int = 0) {}
};

int main ()
{
   using namespace boost::container;

   //리스트안에서 복사할수없고 이동할수없는 오브젝트들을 저장한다
   list<non_copy_movable> l;
   non_copy_movable ncm;

   //한 새로운 요소는 만들어질것이다, non_copy_movable(int)생성자를 호출하면서...
   l.emplace(l.begin(), 0);
   assert(l.size() == 1);

   //한 새로운 요소는 만들어질것이다, 기본 생성자를 호출하면서...
   l.emplace(l.begin());
   assert(l.size() == 2);
   return 0;
}



이하 번역대기........


번역된 페이지 http://www.boost.org/doc/libs/1_51_0/doc/html/container.html

http://www.boost.org/doc/libs/1_51_0/doc/html/container/move_emplace.html

반응형
반응형

Kevlin Henney

소개
예제
참고문서
값 타입 조건들
헤더 <boost/any.hpp>
감사인사

소개

일반적인( 템플릿 기반 프로그래밍에 대조되는 일반적인 의미에서) 타입이 필요합니다

: 실로 변하기 쉬운 변수들, 일반의 엄밀한 그리고 정적인 타입들보다 많은 다른 더 구체적인 타입들의 값에 부합하는 것.

우리는 일반적인 타입의 3가지 기본 종류들을 구분할 수 있습니다.

  • 가능한 값 타입들(예를들면 int 와 string)의 다수중 하나를 유지할 수 있는 변환하는 타입들, 그리고 자유롭게 그들 사이에서 자유롭게 변한다. (예를들면 5 를 "5" 또는 그반대의 경우도 해석하는것)
    그러한 타입들은 스크립팅과 그밖의 해석되어지는 언어 안에서 공통입니다.
    boost::lexical_cast 는 그러한 변환 기능을 제공한다.

  • 다른 타입들의 값 그러나 그들(즉 5는 "5" 또는 5.0 둘중 한쪽으로 절대 변환되어지 않고 int 로서 정확하게 유지된다 )
    사이에서 변환을 시도하지 않는 구별되는 타입들.
    단일값들의 일반적인 컨테이너들, 타입의 인지를 제외하고 해석에 대해 그것들의 동작없음은 그것들을 해석이가능한 변환으로부터 얘기치 않은 일에대해 범위없이 효과적으로 안전하게합니다.

  • 접근과 프로그래머에 대한 해석의 모든 형태들을 맡기면서, 무엇이든 참조할수있는 하지만 실제 기본 타입에대해 염두하지 않는 분간없는 타입들.
    이 일은 void* 에 의해 지배되어집니다 그것은 얘기치 않은 일, 분명하지 않은 행동에 대한 범위의 다량을 줍니다.

( C++ Report 12(7), July/August 2000, Kevlin Henney에 의해 "높이평가되는 변환들" 에서 설명되어진 같은 이름들의 클래스에 기초로되어진)

boost::any 클래스는 두번째 범주에 기반되는 변하기 쉬운 값 타입입니다.

boost::any는 어떤 값 타입과 boost::any의 타입에 정확하게 반대되는 어떤 값의 안전 점검된 추출의 복사를 지원합니다.

더 많은 적절한 연산들을 제공하기때문에, 유사한 디자인은 일반적인 함수 어뎁터(adaptor),any_funtion, 일반적인 iterator adaptor, any_iteator, 그리고 균일한 런타임 처리를 필요로하는 다른 오브젝트 타입들에 사용할수있습니다.

최근 2009 7월 26일, at 21:11:03 +0100 에 수정되었습니다.


예제

다음의 코드는 어떤 오브젝트들의 암시적 변환과 복사를 사용하는 것에 대해 문법을 설명합니다 :


#include <list>
#include <boost/any.hpp>

using boost::any_cast;
typedef std::list<boost::any> many;

void append_int(many & values, int value)
{
    boost::any to_append = value;
    values.push_back(to_append);
}

void append_string(many & values, const std::string & value)
{
    values.push_back(value);
}

void append_char_ptr(many & values, const char * value)
{
    values.push_back(value);
}

void append_any(many & values, const boost::any & value)
{
    values.push_back(value);
}

void append_nothing(many & values)
{
    values.push_back(boost::any());
}

다음은 이전 정의들로부터 흐름을 설명하고 어떤 오브젝트들에 대한 조건들의 사용을 설명합니다 :

bool is_empty(const boost::any & operand)
{
    return operand.empty();
}

bool is_int(const boost::any & operand)
{
    return operand.type() == typeid(int);
}

bool is_char_ptr(const boost::any & operand)
{
    try
    {
        any_cast<const char *>(operand);
        return true;
    }
    catch(const boost::bad_any_cast &)
    {
        return false;
    }
}

bool is_string(const boost::any & operand)
{
    return any_cast<std::string>(&operand);
}

void count_all(many & values, std::ostream & out)
{
    out << "#empty == "
        << std::count_if(values.begin(), values.end(), is_empty) << std::endl;
    out << "#int == "
        << std::count_if(values.begin(), values.end(), is_int) << std::endl;
    out << "#const char * == "
        << std::count_if(values.begin(), values.end(), is_char_ptr) << std::endl;
    out << "#string == "
        << std::count_if(values.begin(), values.end(), is_string) << std::endl;
}

OMG의 property 서비스를 본떠서 만들어 졌기때문에, 타음의 타입들은 임의의 값 타입들에 대해 name-value 쌍들을 정의합니다 :

struct property
{
    property();
    property(const std::string &, const boost::any &);

    std::string name;
    boost::any value;
};

typedef std::list<property> properties;

다음의 기본 클래스는 임의의 인자 타입들 또한 필요로하는 콜벡들에 기반을 둔 런타임 다형성에 하나의 접근을 설명합니다 :

class consumer
{
public:
    virtual void notify(const any &) = 0;
    ...
};



참고문서

ValueType 필요조건들

값들(values)은 독자성이 중요하지 않은 견고한 정보의 오브젝트들이다, 즉 주안점은 대게 그것들의 상태와 그것들 주위에

조직화된 행동이다.

값들에 대해 또 하나의 구별되는 특징은 그것들의 단위이다:

예를들자면 보통은 다수와 같은 시스템안에서 간단한 개념들을 나타내는 조직적인 오브젝트들이다

한 값의 주안점은 그것의 상태안에 놓여있는것으로 그것은 독립성이 아니다,

값들이 복사되어질수 있고 대체적으로 다른것에서 하나가 할당 되어질수 있다,

public 복사생성자와 public 할당 operator의 명시적 또는 묵시적 정의를 필요로 하면서...

값들은 힙에 보다는 대체로 다른 범위들 즉 오브젝트들 또는 블럭들 내부에 남아있다

값들은 그러므로 보통 전달되어지고 곧장 조작되어진다 값들 또는 참조를 통함으로서...

하지만 독립성과 간접적인 방법을 잘 나타내는 포인터로서가 아닌..

any 에 사용되어지기 위한 값타입들에 대한 구체적인 필요조건이다 :

  • ValueType 은 복사생성되어진다[20.1.3].
  • ValueType 은 선택적으로 할당되어진다[23.1]. 강한 예외안전보장은 할당의 모든형태들에 필요하다.
  • ValueType에 대한 파괴자는 예외를던지지않는 예외안정보장성을 유지시킨다.

Header <boost/any.hpp>

namespace boost {
  class bad_any_cast;
  class any;
  template<typename T> T any_cast(any &);
  template<typename T> T any_cast(const any &);
  template<typename ValueType> const ValueType * any_cast(const any *);
  template<typename ValueType> ValueType * any_cast(any *);
}

Copyright © 2001 Kevlin Henney

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)



번역된 원문 http://www.boost.org/doc/libs/1_51_0/doc/html/any.html

http://www.boost.org/doc/libs/1_51_0/doc/html/any/s02.html

반응형
반응형

Eric Niebler

저작권 © 2005, 2006 Eric Niebler

Boost 소프트웨어 라이센스에 의해 배포되어졌다(참부파일을 보세요 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

목록

서문

사용자의 가이드
Accumulators 프레임워크
통계의 Accumulators 라이브러리
감사의 글
참고사항
Accumulators 프레임워크 참고문서
통계적 라이브러리 참고문서
수 연산들 라이브러리 참고문서

서문

정확히 잘못된 것 보다 대략 맞는게 더 낫다

-- 속담

설명

Boost.Accumulators 는 대체적으로 증분 계산을 위한 확장가능한 프레임워크 분만 아니라 증분 통계 계산을 위한 라이브러리 입니다

라이브러리는 accumulator 의 개념을 주로 취급합니다 그리고 accumulator 는 몇몇의 내부상태를 유지하고 한번에 데이터 한 샘플을 받아들이는 기본 계산에관한 엔티티입니다.

이 accumulators는 다른 accumulators에 있는 그들의 계산 몇몇을 떠남길지도 모른다 그리고 다른 accumulators를 accumulators가 의존합니다

Accumulators 는 accumulator 세트 하나와 함께 그룹화되어집니다.

Boost.Accumulators는 한 세트안의 accumulators 와 accumulators가 적절한 명령에서 처리되어지는 것을 보장하는 것 사이에서

상호의존성을 해결합니다

최근 2010년 8월 15일at 23:42:55 GMT 에 수정되었습니다.


유저 가이드

이 섹션은 새로운 accumulators를 생성하기위한 Boost.Accumulators 프레임워크를 사용하는 방법 그리고 증분 통계적 계산을

수행하기 위한 존재하는 통계적 accumulators를 사용하기 위한 방법을 설명합니다

Boost.Accumulators에 구체적인 구성요소에 관한 상세한 정보를 위해서, Reference 섹션을 확인하세요

Hello, World!

아래에 Accumulators 프리엠워크를 사용하는 방법과 증분 통계적 계산을 수행하기 위한 통계적 Accumulators에 대한 완전한 예제가 있습니다.

그것은 평균과 더블(doubles)의 시퀀스에대한 2nd moment(통계학 용어) 를 계산합니다.

#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
using namespace boost::accumulators;

int main()
{
    // 2nd moment와 평균을 계산하는 것을 위한 accumulator 세트를 정의합니다
accumulator_set<double, stats<tag::mean, tag::moment<2> > > acc; // 몇몇의 데이터를 넣습니다 ... acc(1.2); acc(2.3); acc(3.4); acc(4.5); // 결과를 보여줍니다 ... std::cout << "Mean: " << mean(acc) << std::endl; std::cout << "Moment: " << accumulators::moment<2>(acc) << std::endl; return 0; }

이 프로그램은 다음을 보여줍니다:

Mean:   2.85
Moment: 9.635

* 이하 보류(0)


번역된 원문

http://www.boost.org/doc/libs/1_51_0/doc/html/accumulators.html

http://www.boost.org/doc/libs/1_51_0/doc/html/accumulators/user_s_guide.html

반응형

+ Recent posts