C++ :TinySTL 之vector 设计,实现与中间的坑

本文详细介绍了C++中TinySTL的vector实现过程,包括内存管理策略、容量增长方式、构造函数设计以及遇到的问题和解决方案。作者探讨了std::vector内存增长的2的n次方策略,并分享了在实现模板类时遇到的链接错误、编译错误、内存管理问题、max_size()计算困惑等挑战,以及相应的解决办法。此外,还涉及了迭代器的设计与要求,以及在实现erase()和insert()函数时遇到的迭代器失效问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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的限制:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值