C++标准程序库学习笔记

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

fileclass

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);
 
 
 
posted on 2010-03-27 08:22  Chopper  阅读(420)  评论(0编辑  收藏  举报