本篇博客主要针对vector容器的使用事项做讨论,以如何在多线程中使用vector。
一、vector基础
二、vector使用注意事项
不能在后面还会改变vector容量的情况下(添加元素、删除元素),使用指针访问vector里面的元素。 这里原因是当元素的容量增加时,vector的数据存储区容量不够,就会重新申请更大的数据存储区,把原来的数据复制到新的数据存储区,然后释放掉旧的数据存储区,此时,如果有指针指向旧的数据区的数据,这些指针将指向不确定的内容(非法指针),访问这些指针时就会出错,而且这些错误非常值隐蔽,难以发现。典型的场景就是就是多线程的应用中将vector作为容器。主线程不断地像vector中添加数据,多个子线程从vector得到指向某个数据的指针,以方便处理完这个数据之后通过指针更新数据。在这种情况下,由于主线程不断的向vector中添加数据,vector就会重新获取新的数据缓冲区,子线程中获取到的指针就指向不确定内容,程序运行就会出错。
有没有解决非法指针上述问题?当然有:
/** * Array是一个模板类,作用类似于一个vector,但是只实现了部分函数。 * 最大的特点是在多线程环境下通过指针访问数组的元素的是安全的,不会 * 像vector一样出现非法指针,详见博客: * https://blog.csdn.net/DumpDoctorWang/article/details/79966945 * 设计思想是,每当向Array数组的末尾push一个元素时,不是直接将数 * 据本身放进数据容器,而是new一块空间,把数据的值放进去,由于new * 的空间需要手动释放才会失效,因此通过指针访问数组的元素时,除非手 * 动释放了空间,都不会出现异常。然后将新分配空间的指针存储在vector * 里,这样就可以通过指针访问数组元素。这部分详见push()的实现。 */ #ifndef MY_ARRAY_H #define MY_ARRAY_H #include <vector> #include <stdexcept> template<typename T> class Array { public: virtual ~Array() { clear(); } /** * 存入一个元素 * @param elem 元素 */ void push(T &elem) { auto node = new T; //分配空间 (*node) = elem; //赋值 _pointer_vector.push_back(node);//存下指针 } /** * 获取第index个元素的指针 * @param index 索引 * @return 指针 */ T* ptr(std::size_t index) { if (index < _pointer_vector.size()) { return _pointer_vector[index]; } else { clear();//释放内存 throw std::out_of_range("Array::ptr():index超出范围"); } } /** * 重载[]操作符号,提供类似于普通数组通过[]访问元素的功能。 * @param index 索引 * @return 第index个元素的引用 */ T& operator[](std::size_t index){ if (index < _pointer_vector.size()) { return *(_pointer_vector[index]); } else { clear();//释放内存 throw std::out_of_range("Array::ptr():index超出范围"); } } /** * 获取第index个元素 * @param index 索引 * @return 元素 */ T get(std::size_t index) { if (index < _pointer_vector.size()) { return *(_pointer_vector[index]); } else { clear();//释放内存 throw std::out_of_range("Array::get():index超出范围"); } } /** * 用elem更新第index个元素 * @param index 索引 * @param elem 元素 */ void set(std::size_t index, T elem) { if (index < _pointer_vector.size()) { *(_pointer_vector[index]) = elem; } else { clear();//释放内存 throw std::out_of_range("Array::set():index超出范围"); } } /** * 清空所有元素,并释放内存 */ void clear() { for (std::size_t i = 0; i < _pointer_vector.size(); i++) { delete _pointer_vector[i]; } _pointer_vector.clear(); } /** * 返回元素个数 * @return 大于等于0的数 */ size_t size() { return _pointer_vector.size(); } private: std::vector<T *> _pointer_vector; }; #endif //MY_ARRAY_H
Array类的使用非常简单,给出一段示例代码:
int main() { //初始化 Array<int> int_arr; for(int i=0;i<10;i++){ int_arr.push(i);//在数组末尾添加元素 } //打印数组 for(int i=0;i<int_arr.size();i++){ std::cout<<int_arr[i]<<",";//访问元素 // std::cout<<int_arr.get(i)<<",";//这样访问也ok } std::cout<<std::endl; //修改某个数据 int_arr[0] = 23; int_arr.set(1,233); int *pInt = int_arr.ptr(2); *pInt = 2333; //打印数组 for(int i=0;i<int_arr.size();i++){ std::cout<<int_arr[i]<<",";//访问元素 } return 0; }