小明思考

高性能服务器端计算
posts - 70, comments - 428, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

STL 备忘录

Posted on 2006-07-12 11:19 小明 阅读(5660) 评论(14)  编辑 收藏 引用 所属分类: C/C++

[ 不断补充中]

1. string.empty() 不是用来清空字符串,而是判断string是否为空,清空使用string.clear();

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

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

4. 不要用错string.find ,string::find_first_of ,find和find_first_of有本质区别
    find是查找子串在string出现的位置
    find_first_of是查找第一个匹配目标字符串任何一个字符出现的位置。
    (大多数的时候,需要的是find)

5. 用swap技巧来移去string(vector)多余的空间
   vector<int> v ;
   ...
   vector<int>(v).swap(v);

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

7. 了解各种储存bool的优缺点
vector<bool> 第一,它不是一个真正STL容器,第二,它并不保存bool类(Effective STL 18条)
deque<bool> 不连续
vector<char> 太浪费
bitset 不能动态增长
boost::dynamic_bitset 不是标准

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. 如何删除?
vector:
 vector<int> v;
 v.erase(remove(v.begin(), v.end(), 99), v.end());

list:
 list<int> li;
 li.remove(99);

13. 尽量用成员函数代替同名的算法

14. 循环中删除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++);
        else    
            ++iter;
    }

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

16.警惕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
 

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

18.避免iterator失效,不提取无效的iterator
比如:
vector<int> iv;
vector<int>::iterator end = iv .end();
for(int i=0;i<10;++i)
    iv.insert(end,i);
会crash ,因为end指针,随着insert后可能失效
改为:
vector<int> iv;
for(int i=0;i<10;++i)
    iv.insert(iv.end(),i);
或者:
vector<int> iv;
for(int i=0;i<10;++i)
    iv.push_back(i); //prefer


19. 不要把std::auto_ptr用于数组指针
auto_ptr<int> p(new int[10]); //maybe cause memory leak

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

21. 多线程下,几个线程如果共同操作一个容器,安全性(锁)应该由用户自己来实现,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;
   }
//....
}

Feedback

# re: STL 备忘录  回复  更多评论   

2006-07-12 11:34 by 周星星
up一下

# re: STL 备忘录  回复  更多评论   

2006-07-12 15:47 by Arcrest
呵呵,都是Effective STL里面的条目啊
那个12点有点诡异,也容易忘记,不过知道remove的原理就容易记住了

# re: STL 备忘录  回复  更多评论   

2006-07-12 16:10 by 3×7=51
第7条我表示反对,即使它是Meyers说的。我更愿意把它改为"了解vector<bool>的特殊之处"

# re: STL 备忘录  回复  更多评论   

2006-07-12 16:38 by 小明
Meyers说到:
做为一个STL容器,vector<bool>有两个问题.第一,它不是一个真正STL容器,第二,它并不保存bool类型.

vector<bool> v;
bool *pb = &v[0]; // initialize a bool* with the address of
// what vector<bool>::operator[] returns

但是它不能编译.不能的原因是vector<bool>是一个伪容器(pseudo-container),它并不保存真正的bool,而是打包bool以节省空间.

# re: STL 备忘录  回复  更多评论   

2006-07-12 17:22 by 3×7=51
Meyers说的俺知道,可是vector<bool>自然还有它的用途,我们不能因为它不能用在A处,所以就也不把它用于B处。

# re: STL 备忘录  回复  更多评论   

2006-07-12 17:29 by 小明
因为Meyers说过,所以我就不敢用vector<bool>了,我想bitset总是可以替代vector<bool>了。Meyers也来提到了用deque<bool>来代替
所以不用vector<bool>是一种保险/安全的做法。
安全/稳妥第一。

# re: STL 备忘录  回复  更多评论   

2006-07-12 17:34 by 3×7=51
bitset试无法替代vector<bool>因为它无法动态增长。而如果使用deque<bool>则一样无法保证begin到end之间空间的连续。所以似乎也没多大的用处。而bitset跟vector<bool>一样是用位域来表示bool的。

# re: STL 备忘录  回复  更多评论   

2006-07-12 17:42 by 小明
恩,总结一下
vector<bool> Meyers不让用
deque<bool> 不连续
vector<char> 太浪费
bitset 不能动态增长
boost::dynamic_bitset 不是标准

# re: STL 备忘录  回复  更多评论   

2006-07-12 18:21 by 3×7=51
不,我不觉得vector<bool>不可以使用,相反我们可以大胆地使用,反正如果象Meyers说的那种误用了会报错(是否会报错我不确定,是看你们说的,反正我从没那样用过)。

# re: STL 备忘录  回复  更多评论   

2006-07-14 11:25 by darkay
3. 将string转为char * ,用char * t = (char *)s.c_str() 或者 char *t = &s[0] ,而不是 char *t =s.begin();

== 不应该用 &s[0],因为不能假设sting的内部实现的内存是连续的,但是 c_str()返回的则规范要求是连续的。

# re: STL 备忘录  回复  更多评论   

2006-07-14 13:38 by 小明
@darkay
ok,我修改第3条,谢谢

@3×7=51
我修改了第7条,谢谢

# re: STL 备忘录  回复  更多评论   

2006-10-14 21:16 by 罗宾李
不错。
用swap技巧应该是
vector<int>().swap(v);

# re: STL 备忘录  回复  更多评论   

2006-10-16 10:03 by 小明
@罗宾李

表达式vector<int>(v)创建一个临时的vector,它是v的拷贝:vector的拷贝构造函数完成这一工作.但是vector的拷贝构造函数仅申请适合需要的空间来复制.因此临时vector不包含多余空位.然后交换临时对象和v的数据,结果临时对象包含着过多的空间,这些空间曾经是v的,最后,临时对象销毁,并释放空间.Yes,收缩至合适.


所以vector<int>(v).swap(v); 是正确的

# re: STL 备忘录  回复  更多评论   

2007-12-17 17:05 by 秦歌
顶!

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理