容器就是STL中的瓶瓶罐罐,就是能够保存其他类型的对象的类,是STL的关键部件之一。STL的容器分为:顺序容器和关联容器
1.顺序容器
STL中包括三种基本的顺序容器:向量(vector)、线性表(list)、双向队列(deque),基于这三种基本顺序容器,又可以构造出一些专门的容器,用于比较特殊的数据结构,包括堆(heap)、栈(stack)、队列(queue)及优先队列
2.关联容器
vector<int> vecSalary;
list<string> listname;
map<int, Employee*> mapEmployee;//用于存放Employee*指针的map容器
3.操作容器中的数据元素、使用迭代器访问容器中的数据元素
4. 容器中存放对象还是对象指针的选择
当使用基于连续内存的容器时(eg vector容器),在这些容器中插入或删除元素时,往往会引起内存的重新分配或者内存的复制移动,在这种情况下,优先选择存对象的指针;当使用基于节点内存的容器时,当进行数据元素的操作时则很少有内存的复制移动,为了方便这时可以优先包存对象;如果需要保存一些机器资源(eg。文件句柄,命名管道,套接字或者其他类似的资源),通常选择保存指向这些对象的指针。要注意的几点:
1. 小心清理容器中保存的对象指针,如果容器中保存的是对象,那么在容器析构的时候容器会自动清理这些对象。但是,如果容器中保存的是对象的指针,那么这些指针的清理工作就是程序员的责任了。我们应该咋容器使用完毕后没注意清理其中保存的指针,释放这些指针所指向的对象。
vector<Employee*> vecEmployee;
//对容器进行操作
//在容器使用完毕后,清空容器中保存的指针,释放这些指针所指向的对象
for(auto it=vecEmployee.begin(); it!=vecEmployee.end(); ++it)
{
if(NULL != *(it))
delete (*it); //释放指针所指向的对象
(*it) = NULL; //将指针设置为NULL,防止误用
}
vecEmployee.empty(); //清空整个容器
2. 为容器中的对象实现拷贝构造函数和赋值操作符。
如果需要将某个对象保存到容器中,实际上STL会重新生成一个此对象的拷贝,然后将这个拷贝保存在容器中,源对象将不再使用。所以,为了保证将对象装入容器时对象能够被正确地拷贝,需要实现这个对象的类的拷贝构造函数和赋值操作符。
class Employee
{
public:
Employee(const Employee& rsource) //拷贝构造函数
{
*this = rsource; //利用赋值操作符实现对象的拷贝
}
Employee& operator = (const Employee& rsource) //实现赋值操作符,这里对类的每个属性都进行了合理的初始化
{
m_nSalary = rsource.m_nSalary;
m_strName = rsource.m_strName;
return *this;
}
private:
int m_nSalary;
string m_strName;
}
当然,很多时候无须自己实现类的拷贝构造函数,编译器会自动创建一个拷贝构造函数,以拷贝内存的方式完成类对象的拷贝。但是,这里要特别注意的是,内存拷贝并不能保证类对象被正确地拷贝,特别是当类中有指针作为成员属性的时候,需要谨慎地实现自己的拷贝构造函数,以保证类对象在装入容器时能够正确地拷贝。
3. 使用迭代器删除容器中的数据元素需谨慎。当使用迭代器删除容器中的数据元素时,容器中的元素位置将发生变化,所以迭代器所代表的的当前位置也会发生变化,要注意
for(auto it=vecint.begin(); it!=vecint.end(); ++it)
{
if(*it >1000)
it = vecint.erase(it); //删除完成后,将迭代器重新指向正确的位置
}
5. 如何选择合适的容器