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 不是标准