std::vector 是一种封装了动态数组的顺序容器(std::vector
is a sequence container that encapsulates dynamicsize arrays.)
一. 总体设计
1. 内存管理
方案一: 使用std::allocator分配,释放内存(标准STL都是使用std::allocator)
方案二: 使用更加原始的::operatornew 和::operatordelete 来管理内存(operator new/operator delete 和new/delete 表达式不一样,new/delete 表达式既分配内存也初始化对象,operatornew 只分配内存,std::allocator和new/delete表达式都是调用operatornew/operator delete 实现)
方案三: 使用C 语言的malloc/free来管理内存(C 的函数一定比C++的更高效吗?)
目前先实现使用std::allocator 的方案,后实际和理论分析结合判断哪种方案更优
2. 初始内存以及内存增长方式
方案一:
默认内存分配方式为初始分配2*sizeof(T) 大小的内容,随着使用情况,以乘2方式增长内存
方案二:
默认构造时不分配内存,在push 进第一个元素时分配内存(标准STL的实现),增加方式使用2的n 次方
疑问: 为什么std::vector使用 2的n次方这种空间增长方式? 这种方式是最优的吗?
目前先实现方案二,同时继续探索最优的增长方式
3. 构造函数
初期先实现空的构造函数,后续再实现多种指定初值的构造函数
4. Capacity 和size
使用3个指针来标识元素在内存中的情况: first _element指向第一个元素(分配空间的起始位置),end指向分配空间的结束位置,first_free指向未构造元素的第一个位置。故vector的size(实际使用元素数量)= first_element - first_free
Vector 的capacity (在重新分配内存前,可以定义的元素总数) = end – first_element,如下图所示:
二. 目前实现的接口
接口 |
接口类别 |
作用 |
vector<T> |
constructor |
默认构造函数,构造空的vector 对象 |
vector(size_type count,const T& t) |
constructor |
构造函数 |
vector(const vector&); |
constructor |
赋值构造函数,使用已存在vector<T> 类型对象构造一个新的副本 |
size() |
Capacity |
获得vector 当前元素个数 |
capacity() |
Capacity |
获取vector 已分配空间大小 |
void reserver(unsignedlong arg_capacity); |
Capacity |
设置vector 的capacity 大小 |
void shrink_to_fit() |
Capacity |
释放未使用的capacity 空间 |
bool empty() |
Capacity |
判断vector 是否为空 |
max_size() |
Capacity |
给出vector<T> 理论上最大元素个数 |
void push_back(constT& element_t); |
Modifiers |
添加一个元素到vector |
void pop_back() |
Modifiers |
Remove the last element of vector |
void clear() |
Modifiers |
Remove all element of vector. Implemented by calling pop_back() |
void resize(size_type count) |
Modifiers |
Resize the container to hold count elements ,use push_back & pop_back() implement.
|
iterator erase(iterator& pos) |
Modifiers |
Erase element in pos position |
iterator& insert(iterator& pos,constT& value) |
Modifiers |
Insert element before pos |
const T& front()const |
Element access
|
Get first element |
T& front() |
Element access |
Non const front() |
const T& back()const |
Element access
|
Get last element |
T& back() |
Element access |
Non const back() |
const T& at(size_typepos)const |
Element access |
Get the pos element |
T& at(size_typepos) |
Element access |
Non const at |
const T&operator[] (size_typepos)const |
Element access |
Overloaded operator[] |
const T&operator[] (size_typepos) |
Element access |
Non const overloaded operator[] |
T* data() |
Element access |
Returns pointer to the underlying array serving as element storage
暂未实现,待考虑 |
iterator& begin() |
Iterators |
Return iterator to the first element |
iterator& end() |
Iterators |
Return iterator to the element following the last element |
三. 实现过程中遇到的问题与解决
1. 使用模板时,出现链接错误
模板实例化时,编译器需要能看到完整的模板定义代码, 而不像普通函数使用时只需看到声明,模板的编译常见的有两种模型:包含编译模型,分离编译模型
目前主流的编译器如VS等不支持分离编译模型, 故使用包含编译模型
2. 编译时,出现非常多的如下错误:
error C2995: “tiny::vector<T>::~vector(void)”: 函数模板已经定义
还是模板编译的问题,目前来看,模板使用包含编译模型比较好的实践是,将模板声明和实现都放在头文件中,使用模板时include模板头文件即可
参考:http://blog.youkuaiyun.com/xiaoyaohuqijun/article/details/50558208
3. 在向vector 添加第三个元素时,进程卡住不往下走
原因: 在重新分配内存的函数中,delete 操作删除了后续还需要使用的内存或者已经删除了的内存
//doubles the allocated memory
template<classT>voidvector<T>::reallocate()
{
unsigned long _size = first_free - first_element;
unsigned long _capacity = end - first_element;
//allocatenew memory block
T* temp = av.allocate(2 * _capacity);
T* p1 = temp;
T* p2 = first_element;
//copyelement to new memory block and delete element in old memory block
for (unsigned i = 0; i < _size; ++i)
{
av.construct(p1 + i, *(p2 +i));
av.destroy(p2 + i);
}
//freeold memory block
av.deallocate(first_element,_capacity);
//adjust cursor pinters;
first_element = temp;
first_free = first_element +_size;
end = first_element + 2 *_capacity;
deletep1;
delete p2;
}
}
P1 指向新分配的内存,delete p1会导致后面的操作出现未定义行为
P2 指向的内存在前面已经由deallocate 释放,再删除也是未定义的行为
4. 实现max_size() 时的遇到困难,完全没有思路
答: 由于是使用std::allocator来分配内存,某一具体的vector<T>的maxsize 受allocator的限制: