在前面的文章中,我们实现了以下几步:
【简单实现STL容器vector代码】
【⭐️vector容器的空间配置器allocator】
并且我们已经实现了string对象的迭代器,那么今天必然是填vector得坑啦!
【实现string类的迭代器string::iterator】
回顾完前面的文章,现在开整!
提供operator[]
首先我们需要把vector当作数组下标一样来使用。
T& operator[](int index) { // vec[2]
if (index < 0 || index >= size()) {
throw "OutOfRangeException";
}
return _first[index];
}
实现迭代器嵌套类和begin(),end()方法
首先要明确的迭代器一般实现成容器的嵌套类型。这样用户使用起来无感,把底层数据结构的差异性都封装在迭代器中。
再一个,需要提供begin()和end()返回一个迭代器类型,并且分别返回的是特定位置的迭代器。
class iterator {
public:
iterator(T *ptr = nullptr) : _ptr(ptr) {}
private:
T *_ptr;
};
//需要给容器提供begin和end方法
iterator begin() { return iterator(_first); }
iterator end() { return iterator(_last); }
提供operator!=\operator++()
我们只读不写的方法最好写成常方法,这样常量对象和非常量对象都可以调用。有疑问请跳转该文章【把类成员方法声明为常方法的必要性】
bool operator!=(const iterator &it) const {
return _ptr != it._ptr;
}
我们的vector容器底层是一个数组,所以不等于是底层对应的指针不等于。
接下来我们需要重载前置++运算符,如果有不懂的,请移步:【++i和i++的效率问题|重载前置++运算符和重载后置++运算符】
void operator++ () {
_ptr++;
}
容器底层是一个数组,所以迭代器的++就是底层指针的++
重载operator*
迭代器解引用就是容器底层的指针解引用
T& operator*() { return *_ptr; }
在这里我们为什么不用常方法呢,因为我们希望能够利用解引用来个变量赋值:
int data = *it;
当然了,最好的解决办法就是我们再给他提供一个常方法:
const T& operator*() const { return *_ptr; }
测试代码
int main () {
vector<int> vec;
for (int i = 0; i < 20; i++) {
vec.push_back(rand() % 100 + 1);
}
int size = vec.size();
for (int i = 0; i < size; i++) {
std::cout << vec[i] << " ";
}
std::cout << std::endl;
vector<int>::iterator it = vec.begin();
for (; it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
for (int val : vec) { //foreach底层原理就是通过容器的迭代器来实现的容器遍历
cout << val << " "
}
cout << endl;
return 0;
}
没啥毛病!
vector最终代码
template<typename T>
struct Allocator {
T* allocate(size_t size) {//只负责内存开辟
return (T*)malloc(size * sizeof(T));
}
void deallocate(void *p) { // 负责内存释放
free(p);
}
void construct(T *p, const T &val) {//复杂对象构造
new (p) T(val);
}
void destroy(T *p) { //负责对象析构
p->~T(); // ~T()代表了T类型的析构函数
}
};
template <typename T, typename Alloc = Allocator<T> >
class vector {
public:
vector(int size = 10) {
//_first = new T[size];
_first = _allocator.allocate(size);
_last = _first;
_end = _first + size;
}
~vector() {
//delete[] _first;
for(T *p = _first; p != _last; ++p) {
_allocator.destroy(p); //把_first指针指向的数组的有效元素进行析构操作
}
_allocator.deallocate(_first); //释放堆上的内存
_first = _last = _end =nullptr;
}
vector(const vector<T> &rhs) {
int size = rhs._end - rhs._first;
//_first = new T[size];
_first = _allocator.allocate(size);
int len = rhs._last - rhs._first;
for (int i = 0; i < len; ++i) {
//_first[i] = rhs._first[i];
_allocator.construct(_first + i, rhs._first[i]);
}
_last = _first + len;
_end = _first + size;
}
vector<T>& operator=(const vector<T> &rhs) {
if (this == rhs) return *this;
//delete[]_first;
for(T *p = _first; p != _last; ++p) {
_allocator.destroy(p); //把_first指针指向的数组的有效元素进行析构操作
}
_allocator.deallocate(_first); //释放堆上的内存
int size = rhs._end - rhs._first;
//_first = new T[size];
_first = _allocator.allocate(size);
int len = rhs._last - rhs._first;
for (int i = 0; i < len; ++i) {
//_first[i] = rhs._first[i];
_allocator.construct(_first + i, rhs._first[i]);
}
_last = _first + len;
_end = _first + size;
return *this;
}
void push_back(const T &val) {
if (full()) expand();
//*_last++ = val; _last指针指向的内存构造一个值为val的对象
_allocator.construct(_last, val);
_last++;
}
void pop_back() {
if (empty()) return ;
//--_last; 不仅要把_last--,还需要析构删除的元素
--_last;
_allocator.destroy(_last);
}
T back() const { //返回容器末尾元素的值
return *(_last - 1);
}
bool full() const { return _last == _end; }
bool empty() const { return _first == _last; }
int size() const { return _last - _first; }
T& operator[](int index) { // vec[2]
if (index < 0 || index >= size()) {
throw "OutOfRangeException";
}
return _first[index];
}
//迭代器
class iterator {
public:
iterator(T *ptr = nullptr) : _ptr(ptr) {}
bool operator!=(const iterator &it) const {
return _ptr != it._ptr;
}
void operator++() {
_ptr++;
}
T& operator*() { return *_ptr; }
const T& operator*() const { return *_ptr; }
private:
T *_ptr;
};
//需要给容器提供begin和end方法
iterator begin() { return iterator(_first); }
iterator end() { return iterator(_last); }
private:
T *_first; //指向数组起始的位置
T *_last; //指向数组中有效元素的后继位置
T *_end; //指向数组空间的后继位置
Alloc _allocator; //定义容器的空间配置器对象
void expand() { //容器的二倍扩容操作
int size = _end - _first;
//T *ptemp = new T[2 * size];
T *ptemp = _allocator.allocate(2 * size);
for (int i = 0; i < size; ++i) {
//ptemp[i] = _first[i];
_allocator.construct(ptemp + i, _first[i]);
}
//delete[] _first;
for (T *p = _first; p != _last; ++p) {
_allocator.destroy(p);
}
_allocator.deallocate(_first);
_first = ptemp;
_last = _first + size;
_end = _first + 2 * size;
}
};