一、容器的选择
标准STL序列容器:vector,string,deque,list。其中前三种是连续内存容器,list是节点内存容器(非连续内存)
序列容器特点:任意位置删除、插入元素;插入、删除时元素会移动;元素是有顺序的,可以随机访问(list除外),vector数据内存兼容C,string支持引用计数,list支持多元素插入事务性语义(连续内存容器也支持但是性能差);基于节点的非删除迭代器指向元素,迭代器不会失效。
标准STL关联容器:set,mutiset,map,mutimap。
二、编写容器无关代码
1. 使用typedef 如:std::vector<int> 可以写成 typedef std::vector<int> IntContainer;
2. 当容器需要依赖特定方法时,可以对容器就行封装,提供统一的方法(性能稍微有点损耗);
如:
class Container { public: size_t Size(); bool HasNext(); int Next(); ........ private: vector<int> m_vec; }
三、使容器里对象的拷贝轻量且正确
std::vector<Object> vec;
vec.push_back(obj); //会调用Object的拷贝构造函数对元素就行拷贝插入容器中
1.如果上面Object对象比较大,插入元素的代价是比较大的,此时容器应该存对象指针即定义为:std::vector<Object *> vec;担心元素内存释放可用smart_ptr智能指针。
2.当Object是基类时拷贝可能导致累被分割。
四、用empty代替size()检查容器是否为空
1.splice函数和size函数谁是常数时间函数和线性函数时间的取舍问题。size可能是线性时间实现,但empty能肯定是常数时间函数。
五、尽量用区间成员函数代替单元素函数
1.使用区间成员函数:assign,insert ,erase。。。,可以避免手写循环,简化程序并且使程序更直观
如:insert(开始插入位置iterator,插入区间起点,插入区间终点);
六、读取固定格式文件的一种方便实现
ints.dat存放的是一组int值时可以这样读文件
ifstream dataFile("ints.dat"); istream_iterator<int> dataBegin(dataFile); istream_iterator<int> dataEnd; list<int> data(dataBegin, dataEnd);
//上面代码不能这样实现
list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>());//并不是所以编译器都会认
七、一个错误:
class Widget {...}; // 假设Widget有默认构造函数
Widget w(); //编译器会认为是定义了一个不带参数的w函数,返回值为Widget,而不是认为是定义了一个Widget变量w。
八、用for_each和智能指针,管理指针容器中new的元素
1.for_each
std::vector<Object *> vec; struct DeleteObject { template<typename T> void operator()(const T* ptr) const { delete ptr; ptr = NULL; } }; ...//插入元素操作 for_each(vec.begin(), vec.end(), DeleteObject()); //删除元素
2.智能指针
typedef shared_ptr<Object> ShareObj; vector<ShareObj> vec; vec.push_back(ShareObj(new Object));
//注意不要用auto_ptr,auto_ptr会转移对象拥有权
//原因:
对象转移:
auto_ptr<Object> obj1(new Object); //obj1指向一个Object
auto_ptr<Object> obj2(obj1); //obj1指向的对象转移给obj2,obj1指向NULL
obj1 = obj2; //obj1指向Object,obj2指向NULL
进而做以下操作可能发生错误:
auto_ptr<Object> obj = vec[i]; //如果做此操作会使vector中第i个元素对象指向NULL,很容易出现你不想要的结果。
九、不同容器删除元素的方法:
1. vector,string,deque
Container<int> c; //容器为vector,string,deque c.erase(remove(c.begin(), c.end(), 1963), c.end()); //erase remove 惯用法
2.list
list<int> c; c.remove(1123);
3.set, mutiset, map, mutimap等关联容器
set<int> c; c.erase(1212);
4.删除容器中有特定值的元素
bool badValue(int val); Container<int> c c.erase(remove_if(c.begin(), c.end(), badValue), c.end()); //vector,string,deque c.remove_if(badValue); //list //关联容器 for (Container<int>::iterator i = c.begin(); i != c.end(); /*nothing*/ ) { if (badValue(*i)) c.erase(i++); // 对于坏的值,把当前的 else ++i; // i传给erase,然后 } // 作为副作用增加i;
//非关联容器还可以用remove_copy_if函数,先把不删除的的元素拷贝到新的容器,然后把新容器通过swap函数交换到旧容器中
//非关联容器用循环的方法 for (Container<int>::iterator i = c.begin(); i != c.end(); ) { if (badValue(*i)) { i = c.erase(i); // 通过把erase的返回值 } // 赋给i来保持i有效 else { ++i; } }