可以用 back_inserter/front_inserter/inserter 在函数里向容器插入元素
vector<string> vecData;
可以过 reserve预申请足的空间,减少在插入的过程中,由于空间不足,而且导致再申请,影响效率
注意第二个参数的不同,同样是对3个元素排序!!
3. sort/stable_sort
remove( vecData.begin(), vecData.end(), "kong" );
虽然调用了remove,但是容器中的元素数目却不会因此而减少,remove不是真正意思上的删除!!
要真正删除需要再调用erase
vecData.erase( remove( vecData.begin(),vecData.end(), "kong" ), //earse begin
vecData.end() //earse end
);
只有list的remove能真止删除到元素!!真是有点混乱呀!
后面的几个条款平时用得比较少,等有需要时再翻书查了,这里一笔带过
删除容器的指针,并不能删除指针指向的对象
通过mismatch或lexicographical_compare实现简单的忽略大小写的字符串比较
#include <numeric>
int sum = accumulate( vecData.begin(), vecData.end(), 0.0 ); //开始位置,结束位置,初始值
方便快捷,也不用手工写循环体
再加上 multiplies<int>( ) 可以将累加的改为累积
也可以自定义函数:
};
调用:
cout<< sum.x <<" "<<sum.y<< endl;
---------------
也可以使用for_each,先要改写PointAvg
};
cout<< sum.x <<" "<<sum.y<< endl;
第38条:遵循按值传递的原则来设计函数子类
通常使用排序 qsort会以函数指针的形式传比较比函数
void qsort( void* base, size_t nmemb, size_t size, int( *cmpfcn )( const void*, const void*) );
其实直接使用sort会比qsort效率更高,因为sort传入的比较函数子,是以内联方式展开,而qsort是通过指针调用函数,sort减少了函数调用开销,在密集运算时,才会体现出效率上的优势。
对于函数对象的使用,有两点:
1.函数对象必须尽可能小,否则拷贝的开销非常昂贵
2.函数必须是单态的(不是多态),即不能使用虚函数,否则可能出现剥离问题(slicing problem):在对象拷贝过程中,派生部分可能会被去掉,而仅保留了基类部分。
解决办法是:将所需的数据和虚数从函数子类中分离出来,放到一个新的类中;然后在函数子类中包含一个指针,指向这个新类的对象。
比如:有一个包含大量数据且使用了多态性的函数子类:
};
那么,就应该创建一个小巧的,单态类,包含一个指针,指向实现类,并将所有数据,虚函数都放在实现类中:
};
1.注意拷贝构造函数能正确处理到BPFCImpl对象
2.引入shared_ptr来管理比较方便
第39条:确保判别式是“纯函数”
第40条:若一个类是函数子,则应使它可配接
可配接(adaptable)的函数对象,提供了必要的类型定义
如果operator() 只有一个实参,就要继承 unary_function如果有两个,则要继承binary_function
unary_function 必须定义参数类型和返回类型 unary_function<T,void>
同样 binary_function也需要 binary_function<T,T,void>
not1
bind1st() 创建一个函数对象,该函数对象将值V作为第一个参数A。
bind2nd() 创建一个函数对象,该函数对象将值V作为第二个参数B。
关于函数子的详细可看
C++ STL速查手册笔记 http://sinojelly.blog.51cto.com/479153/214389
第41条:
mem_fun定义:
template <typename R, typename C>
mem_fun_t< R, C> mem_fun( R ( C::*pmf ) () ); //C是类,R是成员函数返回值
R ( C::*pmf ) () –> 成员函数指针,mem_fun接受这样的一个成员函数指针,并返回mem_fun_t< R, C>的模板类型,它提供 operator()函数对象,调用通过参数传递进来的成员函数。-> 这样就可以看成是非成员函数的调用了!
class widget {
public:
widget(){};
~widget(){};
void test();
};
void widget::test() { //将成员函数传递给for_each
cout<<"hello"<<endl;
}
Void g_test( widget * w ) {
w->test();
}
int main() {
widget * w =new widget(); // widget w;
vector<widget*> v;
v.push_back( w );
v.push_back( w );
//第一种
for_each( v.begin(), v.end(), g_test );
for_each( v.begin(), v.end(), ptr_fun( g_test) ); //一样效果,ptr_fun指明是非成员函数
//第二,三种
for_each( v.begin(), v.end(), widget::test ); //编译不通过
for_each( v.begin(), v.end(), mem_fun( &widget::test) ); //指针类型使用mem_fun,如果是值类型mem_fun_ref.
delete w;
}
第42条:确保less<T>与operator<具有相同的语义
尽量不要去特列化std名字空间下的模板,大多数情况下有更好的选择
但是也是可以改写的,下面是一个使用auto_ptr特别化less的例子,可编译通过:
}
其实,只要实现一个比较函数子,就不用特例std下的less,不过就是需要在声明容器的时候指定比较函数:
};
multiset<Widget,MaxCompare> widgets;
第43条:算法调用优先手写的循环
通常我们要调用一个容器类的函数时有:
}
也可以用for_each完成:
有几方面的优势:
(1)效率,通常比自己写的循环效率高 -- 自己写部份的lw.end调用了n次,而for_each只调用了1次
(2)正确性,自己写循环更容易出错
(3)可维护性,更加简洁
另外还有关于transform/deque insert/compose2等的讨论
第44条:容器的成员函数优先于同名的算法
特别对于效率至上的程序
如set<int> s;中找一个元素,可以用
s.find( n );
也可以用
find( s.begin(), s.end(), n );
成员函数的查找效率高出100倍以上!!
第45条:正确区分count, find, binary_search, lower_bound, upper_bound和equal_range
在一个未排序的区间里,count用作存在测试,
if( count( lw.begin(), lw.end(), w ) ) {
... //存在
}
如果用find
if( find( lw.begin(), lw.end(), w ) != lw.end() ) {
... //存在
}
从效率来讲, find更高,因为当找到元素时就退出查找,count需要遍历到末尾
在一个排序的区间里,有更好的选择
binary_search/lower_bound/upper_bound/equel_range
binary_search只返回元素是否存在,返回bool,不返回位置
lower_bound指出元素第一个值出现位置,或者适合于插入的位置(不存在时)
upper_bound指向区间中与查找值等价的最后一个元素的下一个位置
equel_range返回一对迭代器,第一个指向与lower_bound相同的迭代器,第二个返回与upper_bound相同的迭代器,注意因为是有序区间内,所以lower_bound与upper_bound之间的元素是相等连续的
也可以用equel_range作存在性判断,同时,也完成了count的工作:
}
cout<< distance( p.first, p.second );
第46条:考虑使用函数对象而不是函数作为STL算法的参数
如有
vector<double> v;
...
sort( v.begin(),v.end(), greater<double>() ); //使用函数对象作为比较
inline bool doubleGreater( double d1, double d2 )
{ return d1 > d2 ; }
sort( v.begin(),v.end(), doubleGreater ); //使用手写的内联函数
通过100w数据对比
greater<double>() 125
doubleGreater 328
通过函数对象效率更高!!
其实函数对象greater<double>::operator() 在编译时期就是以内联展开,才会使得效率提高,但是为什么手工写的内联函数没有相同的效果呢?
这是因为:
doubleGreater 是以指针形式传递到 sort, 会以以下方式展开
void sort( vector<double>::iterator first, vector<double>::iterator second,
bool (*comp)( double, double ) ); //比较函数
参数comp是一个函数指针,编译器通过这个指针调用doubleGreater函数,也就是因为这个指针,抑制了内联机制!!
这也是一个事实: C++的sort比C的qsort效率高!!
第47条:避免产生"直写型"(write-only)的代码
第48条:总是包含(#include)正确的头文件
第49条:学会分析与STL相关的编译诊断信息
通常在VC中使用STL有长长的警告,如何屏蔽stl中的警告
#pragma warning(disable: 4786)
for_each( lw.begin(), lw.end(), mem_fun_ref(&Widget::redraw));