STL备忘录

1. string.find等查找的结果要和string::npos比较,而不是和-1比较。(各个平台可能不同)

2. 将string转为char * ,用char * t = (char *)s.c_str() ,而不是 char *t =s.begin() 或者 char *t = &s[0] 或者 char *t =s.data();

3. vector中的元素被C++标准限定为存储在连续内存中,就像是一个数组。 所以,如果我们想要传递v给这样的C风格的API:void doSomething(const int* pInts, size_t numInts); 可以这么写:

if (!v.empty()) {

doSomething(&v[0], v.size());

}

也可以修改Vector的内容:

vector<double> vd(maxNumDoubles);   // 建立一个vector,它的大小是maxNumDoubles

vd.resize(fillArray(&vd[0], vd.size())); // 让fillArray把数据写入vd,然后调整vd的大小, 为fillArray写入的元素个数

  String可以使用vector<char>作为桥梁。其实所有这类情况都可以使用vector作为桥梁

4. 如何删除?

1) 去除一个容器中有特定值的所有对象:

如果容器是vector、string或deque,使用erase-remove惯用法。

如果容器是list,使用list::remove。

如果容器是标准关联容器,使用它的erase成员函数。

vector:

vector<int> v;

v.erase(remove(v.begin(), v.end(), 99), v.end()); remove全局函数移动指定区间中的元素直到所有“不删除的”元素在区间的开头.

list:

list<int> li;

li.remove(99);

2) 去除一个容器中满足一个特定判定式的所有对象:

如果容器是vector、string或deque,使用erase-remove_if惯用法。

如果容器是list,使用list::remove_if。

如果容器是标准关联容器,使用remove_copy_if和swap,或写一个循环来遍历容器元素,当你把迭代器传给erase时记得后置递增它。

3) 在循环内做某些事情(除了删除对象之外):

如果容器是标准序列容器,写一个循环来遍历容器元素,每当调用erase时记得都用它的返回值更新你的迭代器。

for (SeqContainer<int>::iterator i = c.begin(); i != c.end();){

if (badValue(*i)){

logFile << "Erasing " << *i << '\n';

i = c.erase(i); // 通过把erase的返回值, 赋给i来保持i有效

} // 要记得对于那样的容器,调用erase不仅使所有指向被删元素的迭代器失效,也使被删元素之后的所有迭代器失效

else

++i;

}

下面是倒置方式的实现:

    for(vector<int>::reverse_iterator ri=v.rbegin();ri!=v.rend();)

    {

        if(*ri % 2 == 0)

        {

            cout << "Erasing " << *ri << endl;

            v.erase((++ri).base());

        }

        else ++ri;

    }

 

如果容器是标准关联容器,写一个循环来遍历容器元素,当你把迭代器传给erase时记得后置递增它。

循环中删除map元素的写法

typedef map<int,int> mymap;

typedef map<int,int>::iterator myiter;

mymap m;    m[1] = 2;    m[2] = -1;    m[3] = 3;    m[4] = 0;    m[5] = -5;    m[6] = 1;

myiter iter = m.begin();

    while(iter!=m.end())    {

        if(iter->second<0)   //可以写成一函数

             m.erase(iter++); //i++的值是i的旧值,但作为副作用,i增加了

       else    

            ++iter;

    }

5. 用swap技巧来移去string(vector)多余的空间

   vector<int> v ;

    ...

   vector<int>(v).swap(v); //生成临时对象,然后交换

6. 用vector<char>来储存二进制流;

7. find和find_first_of有本质区别

    find是查找子串在string出现的位置

    find_first_of是查找第一个匹配目标字符串任何一个字符出现的位置。

8. vector resize()和reserve()分别和size和capacity对应,不要搞错

9. vector 的at方法会进行边界检查,[]操作符则不会

10. 使用iterator的时候,自增或者自减,多使用++iter ,--iter的格式。

11. std::mem_fun/std::mem_fun_ref可以将成员函数用来for_each等方法。

std::vector<Employee> emps;

std::for_each(emps.begin(), emps.end(),

        std::mem_fun_ref(&Employee::DoStandardRaise);

std::vector<Employee*> emp_ptrs;

std::for_each(emp_ptrs.begin(), emp_ptrs.end(),

              std::mem_fun(&Employee::DoStandardRaise));

12. 从ifstream读出一行到string,使用std::getline(ifstream的成员函数getline做不到)

13. 警惕string的引用记数技术实现带来的潜在问题

string greet("Hello, world");

string hi(greet);

char *ptr = (char *)hi.c_str();

ptr[0] = 'h';

两个字符串都被修改。

在多线程之间引用多个有关系的string,可能导致引用计数失效,造成多次删除,或者memory leak.

保险的做法是:

string s1("hello") ; string s2 (s1.c_str()); //force copy

14.自定义类放入stl容器中,应注意实现安全的copy ctor和assign operator.尤其是含有指针的class,避免多次删除

15. 不要直接修改set,map的键值,如果要修改,先erase,再insert.

16. 多线程下,几个线程如果共同操作一个容器,安全性(锁)应该由用户自己来实现,stl不保证这一点

例如,一个多线程安全的deque

template<typename T,class ThreadModel=MultiThread>

class CDequePool:private ThreadModel {

  private:

   std::deque<T> m_clDeque;

//.....  

  public:

   bool PutData(const T &data)

   {

    Lock();

    m_clDeque.push_front(data);

    Unlock();

    return true;

   }

//....

}

17. 不要把std::auto_ptr用于数组指针

auto_ptr<int> p(new int[10]); //maybe cause memory leak

18. 了解各种储存bool的优缺点

vector<bool> 第一,它不是一个真正STL容器,第二,它并不保存bool类(Effective STL 18条,其中只是一个位)

deque<bool> 不连续

vector<char> 太浪费

bitset 不能动态增长,编译期已固定大小。

boost::dynamic_bitset 不是标准

你可能感兴趣的:(STL)