1、辅助性“比较操作符”
有四个template functions,分别定义了!=, >, <=, >=四个比较操作符,它们都是利用==, <来完成的,定义于<utility>
namespace rel_ops { // nested namespace to hide relational operators from std template<class _Ty> inline bool operator!=(const _Ty& _Left, const _Ty& _Right) { // test for inequality, in terms of equality return (!(_Left == _Right)); } template<class _Ty> inline bool operator>(const _Ty& _Left, const _Ty& _Right) { // test if _Left > _Right, in terms of operator< return (_Right < _Left); } template<class _Ty> inline bool operator<=(const _Ty& _Left, const _Ty& _Right) { // test if _Left <= _Right, in terms of operator< return (!(_Right < _Left)); } template<class _Ty> inline bool operator>=(const _Ty& _Left, const _Ty& _Right) { // test if _Left >= _Right, in terms of operator< return (!(_Left < _Right)); } }
只需要定义< 和 == 就可以使用它们
#include <utility> class X { public: bool operator==(const X& x) const; bool operator< (const X& x) const; }; void foo() { using namespace std::rel_ops; X x1,x2; ... if(x1 != x2) { } ... if(x1 > x2) { } }
2、用swap提高效率 std::swap(x,y)
3、通过explicit,可以禁止单参数构造函数被用于自动型别转换
4、数值极限 numeric_limits
5、cstddef定义项
NULL
size_t
ptrdiff_t //一种带有正负号的型别,用来表示指针之间的距离
offsetof //表示一个成员在struct或union中的偏移量
#define offsetof(s, m) (size_t)(&(((s *)0)->m))
这是offsetof的标准实现,主要是计算出结构体里成员的相对地址偏移量。
这里使用0只是一个使用的技巧,方便计算出偏移量。
根据成员的地址偏移量以及地址可以计算出宿主结构的地址:
成员地址 - offset = 宿主地址
#define offsetof(s, m) (size_t)(&(((s *)0)->m))
这个宏用来求一个结构体成员相对于这个结构体首地址的偏移量,
例如:
struct Foo{
int x;
};
这个结构体里的成员x,它的相对偏移量就是4;
这个宏里的0是地址,(s *)0,这一步是把从0这个地址开始的一块大小的内存解释成这个结构体类型,&(((s *)0)->m),这一步是取这个结构体程序m的地址,结合Foo这个结构体的例子,如果取成员x的地址,这个地址当然是4,对吧!也就是说,通过这个技巧,我们可以很方便的得到了这个成员偏移量。
size_t其实就是无符号整形,也就是把上面得到的那个地址转成无符号整形
6、 容器
序列式容器:vector, deque, list //每个元素都有固定位置,和元素值无关
关联式容器:set, multiset, map, multimap //有序群集,元素取决于特定的排序准则,位置取决于元素值,和插入次序无关
7、前置式递增要比后置式递增效率高 ++pos 前置 pos++ 后置
8、适用任何容器的程序代码
for(pos = coll.begin(); pos != coll.end(); ++pos) // != 最好不用 <
9、迭代器之配接器
1> Insert iterators
back_inserter, 只有提供push_back成员函数的容器中,这个函数才能使用,有vector, deque, list
front_inserter, 只有提供push_front成员函数的容器中,这个函数才能使用,有 deque, list
inserter, 所有STL容器都提供insert()成员函数,因此这是唯一可用于关联容器的inserter
2> Stream iterators
vector<string> coll; copy(istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(coll)); unique_copy(coll.begin(), coll.end(), ostream_iterator<string>(cout, "\n") );
3> Revers iterators rbegin rend
10、容器内元素条件
1> 必须可通过Copy构造函数进行复制,如果Copy耗费大量时间,可以通过Reference语意使用容器
2> 必须可以通过assignment完成赋值操作
3> 必须可以通过析构函数完成销毁动作
4> 对序列式容器,元素的default构造函数必须可用
5> 对于某些动作,必须定义operator==,以执行相等测试,如果有搜索需求,这一点特别重要
6> 在关联式容器,必须定义出排序准则
11、Map的一个Sample
class RuntimeStringCmp { public: enum cmp_mode { Normal, Nocase }; private: const cmp_mode mode; static bool nocase_compare(char c1, char c2) { return toupper(c1) < toupper(c2); } public: RuntimeStringCmp(cmp_mode m = Normal) :mode(m) {} bool operator() (const string& s1, const string& s2) { if( mode == Normal ) { return s1 < s2; } else { return lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), nocase_compare); } } }; typedef map<string, string, RuntimeStringCmp> StringStringMap; int _tmain(int argc, _TCHAR* argv[]) { StringStringMap col1; col1["a"] = "Germany"; col1["A"] = "german"; col1["b"] = "snag"; StringStringMap ignorecase(RuntimeStringCmp::Nocase); ignorecase["a"] = "Germany"; ignorecase["A"] = "german"; ignorecase["b"] = "snag"; return 0; }
12、advance、distance
advance 可将迭代器的位置增加
distance 处理两个迭代器之间的距离
以上两个函数对于 non-random access迭代器而言,性能并不好,应该尽量避免使用
13、for_each、transform
for_each接收一项操作,该操作可变动参数,因此该参数必须以by reference方式传递
void square(int& elem);
transform 用某操作时,该操作返回被改动后参数
int squre(int elem);
transform的速度稍微慢些,不过其灵活性比较高
14、文件存取class
15、操控器如何运作
ostream& ostream::operator<< (ostream& (*op)(ostream&) )
{
return (*op)(*this);
}
使用
std::ostream& std::endl(std::ostream& strm)
{
strm.put(‘\n’);
strm.flush();
return strm;
}
std::cout << std::endl;
16、文件读取注意事项
int _tmain(int argc, _TCHAR* argv[]) { ifstream file; for(int i = 0; i < argc; ++i) { file.open(argv[i]); char c; while(file.get(c)) { cout.put(c); } file.clear(); //clear eofbit and failbit set due to end-of-file file.close(); } }必须调用clear(),以清除当时被设于文件尾端的状态标志,只是必要的,因为这个stream对象被多个文件共享。open()并不会清除任何状态标志。while循环可以用 std::cout<< file.rdbuf();代替
17、Stream重定向
std::ofstream file(“cout.txt”);std::cout.rdbuf(file.rdbuf());这两句使得写入cout的信息不被送到标准output通道,而是被送到cout.txt文件中1> std::fstream file("example.txt", std::ios::in | std::ios::out); //可以读写2> std::ofstream out("example.txt", ios::in | ios::out);std::istream in(out.rdbuf()); //3> std::filebuf buffer;std::ostream out(&buffer);std::istream in(&buffer);buffer.open("example.txt", std::ios::in | std::ios::out);