[EFFECTIVE STL]
----------------------------------------------------------------------------------------------------
[1 : Containers]
[ITEM 1 : Choose your containers with care]
standard STL sequence containers : vector string, dequeue, list
standard STL associative containers : set, multiset, map, and multimap
----------------------------------------------------------------------------------------------------
[2 : Vector and string]
vector , string 가지고 모든 array 관련 application 대체 가능
1. vector, string의 performance 향상 방법
2. string implemenation의 다양성
[ITEM 13 : Prefer vector and string to dynamically allocated arrays]
[ITEM 16 : Know how to pass vector and string data to legacy APIs]
vector v : &v[0] first element에 대한 포인터
void doSomething(const int * plnts, size_t numInts);
// EMPTY 체크 해야함
if(!v.empty()) doSomething(&v[0], v.size());
char * --> string 으로 대체
void doSomething(const char *p)
string s
// string 이 length 0 이어도 문제 없이 동작 --> null charactor 에 대한 포인터 리턴
// string 은 null character 또한 가질수 있다.
doSomething(s.c_str());
[주의]
시나리오 1 : C API 로 부터 array 사이즈 만큼 초기화 시킨다.
size_t fillArray(double *pArray, size_t arraySize)
vector
vd.resize(fillArray(&vd[0], vd.size());
vector 인 경우는 문제 없는 시나리오 (vector와 array memory layout 은 동일)
시나리오 2 : 시나리오 1인데 string을 초기화 시킨다.
--> vector를 가지고 구현해야만 가능
size_t fillString(char *pArray, size_t arraySize);
vector
// ------------> TERRABLE CODE
// string s;
//size_t charWritten = fillString(s.c_str(), maxNumChars);
size_t charWritten = fillString(&vc[0], vc.size());
string s(vc.begin(), vc.begin() + charWritten);
결론 : C API 사용시 vector에 data를 넣고 해당 STL container에 copy 하는 순서를 따라야함.
void doSomething(const int * plnts, size_t numInts); // C API
set
vector
...
vector
// EMPTY 체크 해야함
if(!v.empty()) doSomething(&v[0], v.size());
string s : s.c_str()
but, certain restriction
----------------------------------------------------------------------------------------------------
[3 : Associative Container]
[ITEM 19 : Understand the difference between equality and equivalence]
EQUQLITY : find algorithm (operator== 사용)
EQUIVALENCE : set::insert (operator< 사용) set
set
bool inserted;
boost::tie(iter,inserted) = ciss.insert("aired");
BOOST_TEST(inserted == true);
boost::tie(iter,inserted) = ciss.insert("AIRED");
BOOST_TEST(inserted == false);
// EQUIVALCE 연산 : CIStringCompare comparation functor 에 의해 equivalent 하나 equal 은 아님
// ITEM44 참고
BOOST_TEST(ciss.find("aired") != ciss.end());
// find algorithm 은 equality 연산 : operator==
// ASSERT FAIL
BOOST_TEST(find(ciss.begin(), ciss.end(),"Aired") != ciss.end());
왜 standard associative container는 equivalence 기반인가? ( 답 ?)
TWO Comparison Function
1 : sorted order 유지 : default less comparison function
Equivalence를 only one comparision function 에서 정의함
2 : Equility 에 대한 default comparision function 존재(equal_to)
그러나 STL 에서는 사용하지 않고 operator== 정의해서 non-member find 알고리즘같은경우도 고려함
[ITEM 20 : Specify comparision types for associative containers of pointers]
* POINTER VALUE 로 sorting 되어있는 associative container 구현
1 : container 의 comparision type을 specify.
2 : deference 작업 필수 (Template으로 구현)
struct DereferenceLess {
template
bool operator()(PtrType pT1, PtrType pT2) const
{
return *pT1 < *pT2; } }; void print(const string *ps){ cout << *ps <<> ssp2;
ssp2.insert(new string("AIRED1"));
ssp2.insert(new string("AIRED2"));
for_each(ssp2.begin(), ssp2.end(), print);
[ITEM21 : Always have comparision functions return false for equal values]
// ITEM21
// WRONG USAGE
set
set
bool inserted2;
boost::tie(iter2,inserted2) = s.insert(10);
BOOST_TEST(inserted2 == true);
// equivalce 가 실패 해서 INSERT 된다.
// !(10A <= 10B) &&amp;amp;amp;amp; !(10B <=10A) // !(true) && !(true) // false && false boost::tie(iter2,inserted2) = s.insert(10); [ITEM 22 : Avoid in-place key modification in set and multiset] [ITEM 23 : Consider replacing associative containers with sorted vectors] set, multiset, map, multimap is OK , 그러나 logrithmic-time lookup speed 능가 하는 constant-time lookup speed 필요 lookup speed 가 중요하다면 non standard hashed container 사용(ITEM25) standard associative container 는 balanced binary search tree로 구현 되어 있다. --> insertion, erase, lookup combination 에 대한 OPTIMIZATION
세가지 DataSturcture 에 대한 사용
1 . Setup :
2 .
3 .
Sorted Vector
- lookup algorithm : binary_search, lower_bound, equal_range
binary serarch tree 를 binary searching 하는것 보다 sorted vector내에서 binary_searching 이 빠른 이유?
1 : size
2 : locality of reference
associative container 의 각 element 당 left, right child node 에 대한 포인터 스페이스 OVERHEAD
vector space overhead 무시 : 3 pointer + 2 pointer + 1 int
vector 는 swap trick 통해 extra space 제거 가능 , 그러나 이자체도 의미가 없다. lookup 동안에는
mermory referencing 이 없슴
morory page 당 몇개 들어갈지 계산하면?
12byte 클래스 , pointer 4byte
4K page 내 : vector(341 entry) , associative container(170 entry)
associative container 사용시 small memory page set 을 클러스터링 할 수 있는 container allocator 구현해야함.
--> tree node 사이에서 locality fo reference 추가 시킴
Sorted Vector : insertion & erasures 에 대한 오버헤드가 큼 , 그렇다 하더라도 associative container
비하면 미비한 오버헤드
insert new element : one 씩 이동 , expensive , reallocate 발생시는 더 큰 오버헤드
map
pair
--> pair
[ITEM 24 : Choose carefully between map::operator[] and map::insert when efficiency is import]
element 존재시 ? operator[] : insert
[ITEM 25 : Familiarize yourself with the nonstandard hashed containers]
----------------------------------------------------------------------------------------------------
[4 : Iterators]
----------------------------------------------------------------------------------------------------
[5 : Algorithms]
[ITEM 30: Make sure destination ranges are big enough]
----------------------------------------------------------------------------------------------------
[6 : Functors, Functor Classes, Functions, etc]
functors : function and function-like object
find_if, for_each ,,, 등등 많은 알고리즘들이 functor를 이용해 control을 제어 한다.
[ITEM38: design functor classes for pass-by-value]
STL function objects are passed by value(i.e., copied) when passed to and from functions
template
Function for_each(InputIterator first, InputIterator last, Function f);
Function object 사용시 2가지 전제 조건
1: function object 자체가 small 해야함
--> pass by value 에 대한 overhead
2: monomorphic 해야함(not polymorphic) --> no virtual function
--> base class, derive class 간 pass-by-value 시 slicing problem 발생
--> Effect C++ ITEM22 , STL ITEM3
but polymorphic functor 자체를 사실상 피하기는 불가능
보통 function object 자체가 크고 polymorphic
bridge pattern으로 해결가능(handle-body)
[ITEM39 : Make predicates pure functions]
predicate : return boool 형태의 function( implicitly bool conversion 도 가능)
predicate 예 : standard associative containers 의 comparison functions , find_if 및 sort
알고리즘에 parameter 로서 패스 된다.
pure function : return value가 parameter 에 의해서만 변하는 function
predicate class : operator() function 이 predicate 인 functor 클래스
중요 : predicate function 들을 pure function 을 만족해야함.
functor 클래스는 1개의 operator() function 을 가짐
unary_function binary_function 을 상속받는 이유
--> adaptable function object를 만들기 위함
--> not1, bind2nd 자체도 adaptable function object와 같이 동작
---------------------------------------------------------------------------------------------------------
[7 : Programming with the STL]
ITEM 43 : Prefer algorithm calls to hand-written loops
vector<u> vector;
for(vector<u>::iterator i = vector.begin(); i!= vector.end(); ++i)
i->redraw();
for_each(vector.begin(), vector.end(), mem_fun(&U::redraw));
1. Efficiency
2. Correctness
3. Maintainablility
ITEM 44 : Prefer member functions to algorithms with the same names
1. FAST
2. container 에 맞게 integrating.
associative container : count, find, lower_bound, upper_bound, equal_range
list container : remove, remove_if, unique, sort, merge, reverse
ITEM 45 : Distinguish among cuont, find, binary_search, lower_bound, upper_bound, and equal_range
p 200 표 참고
-----------------------------------------------------------------------------------------------
댓글 없음:
댓글 쓰기