之前已经完成了STL中容器的梳理,那么从语言的层面来看:
- 容器是class template
- 算法是function template
- 迭代器是class template
- 适配器是class template
- 分配器是class template
一般STL中的算法都是如下的两种形式(Algorithm代表一种泛指,可以替代其他的函数名称)
template
Algorithm (Iterator itr1, Iterator itr2)
{
..........
}
template
Algorithm (Iterator itr1, Iterator itr2, Cmp comp)
{
..........
}
对于Algorithms来说,是不能直接看到Container的,对他的情况可谓一无所知。那么,他所需要的一切信息就必须要通过他们之间桥梁Iterators来获得了。然而Iterators(是由Container所提供的)必须能够回答Algorithms所提出的一些问题(比如类型等),才能够搭配对应的Algorithm的所有操作。
所谓算法的所提出的问题,其hi就是类型的确认过程,通过确认,来获取他所需要的,例如标记了五种iterator categories的类型
//5种iterator categories
struct input_iterator_tag{};
//
struct output_iterator_tag{};
//
struct forward_iterator_tag : public input_iterator_tag{};
//forward_list是单向链表
struct bidirectional_iterator_tag : public forward_iterator_tag{};
//list,rb_tree为底层的set,multiset、map、multimap是双向链表,iterator不能随机跳跃
struct random_access_iterator_tag : public bidirectional_iterator_tag{};
//对于连续空间的array、vector、deque
(虽然实际上不连续,但是iterator构造了连续的假象)
,这些迭代器可以随便跳跃的类型
这样设计的优势是在于,通过对象的方式就可以调用不同函数的重载,例如:
void _display_category(random_access_iterator_tag){
cout << "random_access_iterator" << endl;
}
void _display_category(bidirectional_iterator_tag){
cout << "bidirectional_iterator" << endl;
}
void _display_category(forward_iterator_tag){
cout << "forward_iterator" << endl;
}
void _display_category(input_iterator_tag){
cout << "input_iterator" << endl;
}
void _display_category(output_iterator_tag){
cout << "output_iterator" << endl;
}
template
void display_category(I iter){
typename iterator_traits::iterator_category cagy;
_display_category(cagy);
//根据对象类型,可以调用不同的函数重载
}
//.........
{
//通过iterator的临时对象来作为参数调用
display_category(set::iterator());
}
- istream_iterator 的iterator_category
gnu2.9里面的istream_iterator
template
class istream_iterator{
public:
typedef input_iterator_tag iterator_category;
// ............
};
gnu 3.3里面的istream_iterator
template,
class _Dist = ptrdiff_t>
class istream_iterator{
public:
typedef input_iterator_tag iterator_category;
}
Gnu4.9里面的istream_iterator
template
struct iterator{
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
}
template,
typename _Dist = ptrdiff_t>
class istream_iterator: public iterator
{...........}
- ostream_iterator 的iterator_category
gnu2.9里面的ostream_iterator
template
class ostream_iterator{
public:
typedef output_iterator_tag iterator_category;
// ............
};
gnu 3.3里面的ostream_iterator
template,
class _Dist = ptrdiff_t>
class ostream_iterator{
public:
typedef output_iterator_tag iterator_category;
}
Gnu4.9里面的ostream_iterator
template
struct iterator{
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
}
template,
typename _Dist = ptrdiff_t>
class ostream_iterator: public iterator
{...........}
- iterator_category对算法的影响
template
inline iterator_trais::diference_type __distance(InputIterator first, InputIterator last, input_iterator_tag){
//input_iterator_tag是forward_iteator_tag和bidirectional_iterator_tag的父类,
//所以遇到了会直接进入input_iterator_tag的重载部分
iterator_trais::difference_type n = 0;
//由于不是RandomAccessIterator,所以迭代器不能直接相减,需要遍历了
while(first != last){
++first;
++n;
}
return n;
}
template
inline iterator_trais::difference_type __distance(RandomAccessIterator first, RandomAccessIterator last, random_access_iterator_tag){
return last - first;
//只有连续空间才能迭代器想减
}
template
inline iterator_trais::difference_type distance(InputIterator first, InputIterator last){
//根据trais获取iterator的category tag,如果编译不通过说明迭代器出问题
typedef typename iterator_trais::iterator_category category;
return __distance(first, last, category());
//根据第三参数调用了不同的函数重载
}
以copy()函数为例,说明STL算法设计的思路,针对不同的类型的Iterator进行了详细的区分和判断,选择最高效的方法来赋值需要复制的内容
算法的效率与他是否能够判断出iterator的分类很重要。
算法源码中,对于iterator_category都是采用“暗示”的方式,因为算法主要为模版函数,而模版函数可以传入任何的类型,所以只是定义模版的时候定义为需要的迭代器名字,但并不是真正的区分类型。如果传入的类型不正确,编译会不通过,采用这样的方式来区分iterator的类型
部分算法源码剖析
- c语言的算法函数样例
qsort(c.data(), ASIZE, sizeof(long), compareLongs);
long* pItem = (long*) bsearsh(&target, (c.data()), ASIZE, sizeof(long), compareLongs);
- C++标准库的函数样例
template
std::Algorithm (Iterator itr1, Iterator itr2)
{
..........
}
template
std::Algorithm (Iterator itr1, Iterator itr2, Cmp comp)
{
..........
}
- 算法accumulate
template
T accumulate(InputIterator first, InputIterator last, T init)
{
for( ; first != last; ++first)
{
//将元素累加至初值init上
init = init + *first;
}
return init;
}
template
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op)
{
for( ; first != last; ++first)
{
//对元素“累加计算(具体算法可以通过传入一个函数指针或者函数对象来指定)”至初值init上
init = binary_op(init, *first);
}
return init;
}
用例
int myfunc(int x, int y){return x + 2 * y;}//一般的函数
struct myclass{
int operator()(int x, int y){return x + 3 * y; }
} myobj; //函数对象(仿函数)
void test
{
int init = 100;
int nums[] = {10, 20, 30};
accmulate(nums, num + 3, init); //160
accumulate(nums, num + 3, init, minus); //使用了stl的相减的函数 40
accumulate(nums, num + 3, init, myfunc); //220
accumulate(nums, num + 3, init, myobj); //280
}
- 算法for_each
template
Function for_each(InputIterator first, InputIterator last, Function f)
{
for( ; first != last; ++first)
{
f(*first);
}
return f;
}
用例
void mufunc(int i){
cout << ' ' << i;
}
typedef struct myclass{
void operator() (int i){
cout << ' ' << i;
}
} myobj;
void test()
{
vector myvec;
myvec.push_back(10);
...........
for_each(myvec.begin(), myvec.end(), myfunc);//循环调用自定义函数
for_each(myvec.begin(), myvec.end(), myobj);//循环调用仿函数(函数对象)
}
- 算法replace,replace_if , replace_copy
template
void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value)
{
//范围内所有等同于old_value者都以new_value取代
for( ; first != last; ++first){
if(*first == old_value)
*first = new_value;
}
}
template
void replace_if(ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value)
{
//范围内所有满足pred()为true的元素都以new_value取代
for( ; first != last; ++ first)
if(pred(*first))
*first = new_value;
}
template
OutputIterator replace_copy(InputIteator first, InputIterator last, OutputIterator result, const T& new_value, const T& old_value)
{
//范围内所有等同于old_value者,都以new_value防止新的区间
//不符合者原值放入新区间
for( ; first != last; ++first, ++ result)
*result = *first == old_value? new_value: *first;
return result;
}
- 算法count, count_if
template
typename iterator_traits::difference_type count(InputIterator first, InputIterator last, const T& value){
//以下定义一个初值为0的计数器n
typename iterator_traits::difference_type n = 0;
for( ; first != last; ++first)
if(*first == value)
++n;
return n;
}
template
typename iterator_traits::difference_type count_if(InputIterator first, InputIterator last, Predicate pred){
//以下定义一个初值为0的计数器n
typename iterator_traits::difference_type n = 0;
for( ; first != last; ++first)
if(pred(*first)
++n;
return n;
}
容器不带成员数count():array、vector、list、forward_list、deque
容器带有*成员函数count():set、multiset、map、multimap、unordered_set、unordered_multiset、unordered_map、unordered_multimap
容器自带count的应该使用自己所带有的count效率较高,而不在容器内的count函数实际是泛化版本,相对效率较低
因为hashtable 和rb_tree是具有自己严谨的结构,所以有自己的count成员函数
- 算法find、find_if
template
InputIterator find (InputIterator first, InputIterator last, const T& value)
{
while(first != last && *first != value)
++first;
return first;
}
template
InputIterator find_if(InputIterator first, InputIterator last, Predicate pred)
{
while(first != last && !pred(*first))
++first;
return firstl
}
容器不带成员数find():array、vector、list、forward_list、deque
容器带有*成员函数count():set、multiset、map、multimap、unordered_set、unordered_multiset、unordered_map、unordered_multimap
容器自带find的应该使用自己所带有的find效率较高,而不在容器内的count函数实际是泛化版本,相对效率较低
因为hashtable 和rb_tree是具有自己严谨的结构,所以有自己的find成员函数
- 算法sort
容器不带成员函数sort():array、vector、deque、set、multiset、map、multimap、unordered_set、unordered_multiset、unordered_map、unordered_multimap
关联式容器本身就已经完成了排序的任务,所以他没有sort的成员函数
容器带有成员函数sort
list、forward_list
泛化的sort需要传入的是RandomAccessIterator才能够排序,对于list和forward_list的迭代器并不是,如果他们使用泛化的sort会无法通过编译
仿函数functors
//算术类(Arithmetic)
template
struct plus:public binary_function
{
T operator()(const T& x, const T& y) const { return x + y; }
};
template
struct minus: public binary_function
{
T operator() (const T& x, const T& y)const
{
return x - y;
}
};
//逻辑运算类(Logical)
template
struct logical_and : public binary_function{
bool operator() (const T& x, const T& y) const { return x && y; }
};
//相对关系类(比大小 Relational)
template
struct equal_to : public binary_function{
bool operator()(const T& x, const T& y) const { return x == y; }
};
template
struct less: public binary_function{
bool operator() (const T& x, const T& y) const { return x < y; }
}
//GNU 独有非标准
template
struct identity: public unary_function{
const T& operator() (const T& x) const {return x;}
};
template
struct select1st: public unary_function{
const typename Pair::first_type& operator() (const Pair& x) const{
return x.first;
}
}
template
struct select2nd: public unary_function{
const typename Pair::second_type& operator() (const Pair& x) const {
return x.second;
}
}
template
struct pair{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() : first(T1()), second(T2()){}
pair(const T1& a, const T2& b):first(a),
second(b){}
};
目的是为了将这些操作的方法传给算法来使用,所以必须是定义函数或者是定义仿函数的方式来实现
每个标准库所提供的仿函数都有继承关系,“binary_function
template
struct unary_function{
typedef Arg argument_type;
typedef Result result_type;
};
template
struct binary_function{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
}
以上两个类,理论大小为0,实际应该为1,但是当他作为父类的时候,他所占的空间的大小为0
stl规定,每个Adaptable Function都应该挑选上面的两个类进行继承,如果不继承,将不具备adaptable的条件,方便Adapter获取到其中的typedef的一些类型名称,以便获取到相关的模版类型。
仿函数,实际就是class、struct重载()操作符,实际对象就可以像函数一样使用
存在多种Adapter
- 容器适配器 stack、queue
template >
class stack{
//.......
public:
typedef typename Squence::value_type value_type;
typedef typename Squence::size_type size_type;
typedef typename Squence::reference reference;
typedef typename Squence::const_reference const_reference;
protected:
Sequence c; //底层容器
public:
bool empty() const {return c.empty();}
size_type size() const {return c.size();}
reference top() {return c.back();}
const_reference top() const {return c.back();}
void push (const value_type& x) { c.push_back(x);}
void pop() {c.pop_back();}
}
template >
class queue{
//.............
public:
typedef typename Squence::value_type value_type;
typedef typename Squence::size_type size_type;
typedef typename Squence::reference reference;
typedef typename Squence::const_reference const_reference;
protected:
Sequence c; //底层容器
public:
bool empty() const {return c.empty();}
size_type size() const {return c.size();}
reference front() {return c.front();}
const_reference front() const {return c.front();}
reference back() {return c.back();}
const_reference back() const {return c.back();}
void push (const value_type& x) { c.push_back(x);}
void pop() {c.pop_front();}
}
- 函数适配器(Function Adapter)binder2nd
cout << count_if(vi.begin(), vi.end(), bind2nd(less(), 40);
//辅助函数,让使用者方便使用binder2nd
//编译器自动推到Op的type
template
inline binder2nd bind2nd(const Operation& op, const T& x){
typedef typename Operation::second_argument_type arg2_type;//封装模版传入的类型
return binder2nd(op, arg2_type(x));//通过return-by-value的形式,返回了binder2nd值
}
//将够格Adaptable Binary Function 转换为Unary Function
template
class binder2nd: public unary_function
//count_if的代码
template
typename iterator_traits::difference_type count_if(InputIterator first, InputIterator last, Predicate pred){
//以下定义一个取初值为0的计数器
typename iterator_traits::differece_type n = 0;
for( ; first != last; ++first) //遍历
if(pred(*first)) //如果元素带入pred的结果为true
//实际
++n;
}
注:模版参数Operation,其中定义有类型为
typename Operation::second_argment_type value;
,对于示例中的操作传入的是是less的,其中,如果查看之前的所写的内容,可以看到less的代码,less继承了binary_function,而在binary_function中仅仅定义了几个typedef而已,正好方便确认模版参数的类型
//less的代码
template
struct less: public binary_function{ //继承了binary_function
bool operator() (const T& x, const T& y) const { return x < y; }
}
//binary_function和unary_function的代码
template
struct unary_function{
typedef Arg argument_type;
typedef Result result_type;
};
>
template
struct binary_function{
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
}
随着发展,现在的stl也发生了一些变化,接下来我们来看看变化的情况:
| 最新 | 以前 |
| ------------- |: -----:|
|, basic_stringbuf| , strstreambuf|
|, basic_istringstream| , istrstream|
|, basic_ostringstream | , ostrstream|
|, basic_stringstream| , strstream|
|, hash_set|
|, unordered_multiset| , hash_multiset|
|, unordered_map| , hash_map|
|, unordered_multimap| , hash_multimap|
|, bind| , binder1st|
|, bind| , binder2nd|
|, bind| , bind1st|
|, bind| , bind2nd|
|, unique_ptr| , auto_ptr|
- not1
//使用
cout << count_if(vi.begin(), vi.end(), not1(bind2nd(less(), 40);
template
inline unary_negatenot1(const Predicate& pred){
return unary_negate(pred);
}
template
class unary_negate:public unary_function{
protected:
Predicate pred; //内部成员
public:
explicit unary)negate(const Predicate& x): pred(x){}
bool operator()(const typename Predicate::argument_type& x) const{
return !pred(x);
}
}
template
typename iterator_traits::difference_type count_if(InputIterator first, InputIterator last, Predicate pred){
typename iterator_traits::difference_ytpe n = 0;
for( ; first != last; ++first)
if(pred(*first))
++n;
return n;
}
- bind
std::bind可以绑定:
1 functions
2 function objects
3 member functions: 必须是某个object地址
4 data members:必须是某个object的弟子,返回一个Function object ret, 调用ret相当于上述1 2 3 或相当于取出4
#include // std::cout
#include // std::bind
// a function: (also works with function object: std::divides my_divide;)
double my_divide (double x, double y) {return x/y;}
struct MyPair {
double a,b;
double multiply() {return a*b;}
};
int main () {
using namespace std::placeholders; // adds visibility of _1, _2, _3,...
// binding functions:
auto fn_five = std::bind (my_divide,10,2); // returns 10/2
std::cout << fn_five() << '\n'; // 5
auto fn_half = std::bind (my_divide,_1,2); // returns x/2
std::cout << fn_half(10) << '\n'; // 5
auto fn_invert = std::bind (my_divide,_2,_1); // returns y/x
std::cout << fn_invert(10,2) << '\n'; // 0.2
auto fn_rounding = std::bind (my_divide,_1,_2); // returns int(x/y)
std::cout << fn_rounding(10,3) << '\n'; // 3
MyPair ten_two {10,2};
// binding members:
auto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply()
std::cout << bound_member_fn(ten_two) << '\n'; // 20
auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a
std::cout << bound_member_data() << '\n'; // 10
return 0;
}
关于bind的原理较为复杂,在这里就不做详细的分析了,但是可以给出两个参考文章,来说明bind的实现原理
std::bind技术内幕
std bind 原理简单图解
- reverse_iterator
template
class reverse_iterator{
protected:
Iterator current;
public:
typedef typename iterator_traits::iterator_category iterator_category;
typedef typename iterator_traits::iterator_type iterator_type;
//.........
typedef Iterator iterator_type;
typedef reverse_iterator self;
public:
explicit reverse_iterator(iterator_type x):current(x){}
reverse_iterator(const self& x):current(x.current){}
iterator_type base() const{return current;}
reference operator*() const {Iterator tmp = current; return *--tmp;}
pointer operator->() const {return &(operator*();}
self& operator++() {--current; return *this;}
self& operator--(){ ++current; return *this;}
self operator+(difference_type n) const {return self(current - n); }
self operator-(difference_type n) const {return self(current + n); }
}
- 迭代器适配器:inserter
//copy
template
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result){
while(first != last){
*result = * first;
++result;
++first;
}
return result;
}
//copy的一般使用
int myints[] = {10, 20, 30, 40, 50, 60, 70};
vector myvec(7);
copy(myints, myints + 7 , myvec.begin());
list foo, bar;
for(int i = 1; i <= 5; i++){
foo.push_back(i);
bar.push_back(i * 10);
}
list::iterator it = foo.begin();
advance (it, 3);
copy(bar.begin(), bar.end(), insert(foo, it));
template
class insert_iterator{
protected:
Container* container;
typename Container::iterator iter;
public:
typedef output_iterator_tag iterator_category;
insert_iterator(Container& x, typename Container::iterator):container(&x), iter(i){}
insert_iterator& operator= (const typename Container::value_type& value){
iter = container->insert(iter, value);
++iter;
return *this;
}
};
template
inline insert_iterator inserter(Container& x, Iterator i){
typedef typename Container::iterator iter;
return insert_iterator(x, iter(i));
}
注:在copy中,第三参数,传入了一个inserter函数的执行结果后,
*result = *first;
的代码的result实际就是insert_iterator对象,这个对象中重载了=操作符,在result指向=时,就会调用重载的操作符,以实现,拷贝的同时还在移动原集合的内容
- ostream_iterator
//用例
#include // std::cout
#include // std::ostream_iterator
#include // std::vector
#include // std::copy
int main () {
std::vector myvector;
for (int i=1; i<10; ++i) myvector.push_back(i*10);
std::ostream_iterator out_it (std::cout,", ");
std::copy ( myvector.begin(), myvector.end(), out_it );
return 0;
}
//实现代码
template >
class ostream_iterator :
public iterator
{
basic_ostream* out_stream;
const charT* delim;
public:
typedef charT char_type;
typedef traits traits_type;
typedef basic_ostream ostream_type;
ostream_iterator(ostream_type& s) : out_stream(&s), delim(0) {}
ostream_iterator(ostream_type& s, const charT* delimiter)
: out_stream(&s), delim(delimiter) { }
ostream_iterator(const ostream_iterator& x)
: out_stream(x.out_stream), delim(x.delim) {}
~ostream_iterator() {}
ostream_iterator& operator= (const T& value) {
*out_stream << value;
if (delim!=0) *out_stream << delim;
return *this;
}
ostream_iterator& operator*() { return *this; }
ostream_iterator& operator++() { return *this; }
ostream_iterator& operator++(int) { return *this; }
};
- istream_iterator
//用例
#include // std::cin, std::cout
#include // std::istream_iterator
int main () {
double value1, value2;
std::cout << "Please, insert two values: ";
std::istream_iterator eos; // end-of-stream iterator
std::istream_iterator iit (std::cin); // stdin iterator
if (iit!=eos) value1=*iit;
++iit;
if (iit!=eos) value2=*iit;
std::cout << value1 << "*" << value2 << "=" << (value1*value2) << '\n';
return 0;
}
//实现代码
template , class Distance=ptrdiff_t>
class istream_iterator :
public iterator
{
basic_istream* in_stream;
T value;
public:
typedef charT char_type;
typedef traits traits_type;
typedef basic_istream istream_type;
istream_iterator() : in_stream(0) {}
istream_iterator(istream_type& s) : in_stream(&s) { ++*this; }
istream_iterator(const istream_iterator& x)
: in_stream(x.in_stream), value(x.value) {}
~istream_iterator() {}
const T& operator*() const { return value; }
const T* operator->() const { return &value; }
istream_iterator& operator++() {
if (in_stream && !(*in_stream >> value)) in_stream=0;
return *this;
}
istream_iterator operator++(int) {
istream_iterator tmp = *this;
++*this;
return tmp;
}
};