深入理解C++ Vector类的实现及测试
引言
在C++中,标准模板库(STL)的
std::vector
是一个强大的动态数组容器。然而,为了更好地理解其内部机制和学习模板类的实现方式,我们可以亲自动手实现一个简化版的 Vector 类。在本文中,我们将介绍自定义的 Vector 类,并通过测试用例展示其功能。
本篇面向的是初学者,旨在帮助他们了解vector的实现。
提供详细的过程的同时附源码,也是为了让自己的进步,共勉之。
Vector 类主要成员和构造函数
template <typename T>
class Vector {
public:
typedef T value_type;
typedef T* iterator;
Vector() : _start(nullptr), _finish(nullptr), _end(nullptr) {}
// ...
private:
iterator _start;
iterator _finish;
iterator _end;
};
Vector
是一个模板类,使用T
表示元素的类型。value_type
定义了元素的类型,iterator
定义了迭代器类型。_start
、_finish
和_end
是迭代器,用于跟踪容器的起始、元素结束和容器末尾位置。
push_back 函数
void push_back(const value_type &x) {
if (capacity() == 0 || capacity() == size()) {
reserve((capacity() == 0) ? 1 : capacity() * 2);
}
*_finish = x;
++_finish;
}
push_back
将元素添加到容器的末尾。- 如果容器的容量为零或者容量已满,调用
reserve
函数进行扩容。 - 将元素添加到
_finish
指向的位置,然后将_finish
向后移动。
pop_back 函数
void pop_back() {
if (!empty()) {
--_finish;
std::cout << "弹出元素: " << *_finish << std::endl;
} else {
std::cout << "容器为空,无法弹出元素." << std::endl;
}
}
pop_back
从容器末尾弹出一个元素。- 如果容器不为空,将
_finish
向前移动一个位置,并打印弹出的元素。 - 如果容器为空,输出一条相应的提示信息。
reserve 函数
void reserve(size_t newCapacity) {
value_type* tmp = new value_type[newCapacity]();
size_t size1 = size();
if (_start) {
for (size_t i = 0; i < size1; i++) {
tmp[i] = _start[i];
}
}
delete[] _start;
_start = tmp;
_finish = _start + size1;
_end = _start + newCapacity;
}
reserve
函数用于预留足够的容量,以便存储指定数量的元素。- 创建一个新的数组
tmp
,将原有元素复制到新数组。 - 释放原有内存,将
_start
指向新数组,更新_finish
和_end
。
insert 函数
void insert(const value_type &x, const size_t &pos) {
if (pos > size()) {
cout << "越界: 无法在指定位置插入元素." << endl;
return;
}
if (capacity() == 0) {
reserve(1);
*_finish = x;
++_finish;
} else if (size() == capacity()) {
size_t size1 = size();
size_t cap = capacity();
value_type* tmp = new value_type[2 * capacity()]();
for (size_t i = 0; i < pos; i++) {
tmp[i] = _start[i];
}
tmp[pos] = x;
for (size_t i = pos; i < size1; i++) {
tmp[i + 1] = _start[i];
}
delete[] _start;
_start = tmp;
_finish = _start + size1 + 1;
_end = _start + 2 * cap;
} else {
for (int i = size(); i > pos; i--) {
_start[i] = _start[i - 1];
}
_start[pos] = x;
_finish = _start + size() + 1;
}
}
insert
函数用于在指定位置插入元素。- 如果插入位置超出当前元素个数,输出提示信息并返回。
erase 函数
void erase(const size_t &pos) {
if (pos >= 0 && pos < size()) {
iterator begin = _start + pos;
while (begin != _finish) {
*begin = *(begin + 1);
++begin;
}
--_finish;
//--_end;
} else {
std::cout << "越界: 无法删除指定位置的元素." << std::endl;
}
}
erase
函数用于删除指定位置的元素。- 如果位置合法,从指定位置开始,将后续元素向前移动一个位置。
- 更新
_finish
和_end
,删除最后一个元素。
这些关键代码片段涵盖了 Vector 类的核心功能,包括元素的添加、删除、扩容等操作。
判空函数 empty()
cppCopy codebool empty() const {
return _start == _finish;
}
- 作用: 判定容器是否为空。
- 解释:
_start
和_finish
是迭代器,它们指向容器的起始和元素结束位置。如果它们相等,说明容器为空,返回true
;否则返回false
。
打印函数 Print()
cppCopy codevoid Print() {
if (empty()) {
std::cout << "容器为空." << std::endl;
return;
}
std::cout << "容器元素: ";
for (size_t i = 0; i < size(); i++) {
std::cout << _start[i] << " ";
}
std::cout << std::endl;
}
- 作用: 打印容器中的元素。
- 解释:
- 首先,通过调用
empty()
判定容器是否为空。 - 如果为空,输出提示信息。
- 否则,使用循环遍历容器中的元素,并输出到控制台。
- 首先,通过调用
计算元素个数函数 size()
cppCopy codesize_t size() const {
return _finish - _start;
}
- 作用: 获取容器中元素的个数。
- 解释:
_finish
和_start
分别指向元素结束和容器起始位置,通过它们的差值可以得到容器中元素的个数。
计算容器长度函数 capacity()
cppCopy codesize_t capacity() const {
return _end - _start;
}
- 作用: 获取容器的总长度(即容器的总容量)。
- 解释:
_end
和_start
分别指向容器的末尾和起始位置,通过它们的差值可以得到容器的总长度,即容器的总容量。
这些函数提供了对容器状态的查询和展示功能,使用户能够更方便地了解容器的结构和内容。在实际应用中,这些操作通常是基础而重要的。
完整代码:
/*************************************************************************
> File Name: Vector.cpp
> Author:
> Mail:
> Created Time: Sun Nov 5 17:40:52 2023
************************************************************************/
#include <iostream>
#include <cassert>
#include <string>
using namespace std;
#define BEGINS(x) namespace x{
#define ENDS(x)}
template <typename T>
class Vector {
public:
typedef T value_type;
typedef T* iterator;
Vector() : _start(nullptr), _finish(nullptr), _end(nullptr) {}
size_t size() const {
return _finish - _start;
}
size_t capacity() const {
return _end - _start;
}
void push_back(const value_type &x) {
if (capacity() == 0 || capacity() == size()) {
reserve((capacity() == 0) ? 1 : capacity() * 2);
}
*_finish = x;
++_finish;
}
void pop_back() {
if (!empty()) {
--_finish;
cout << "弹出元素: " << *_finish << endl;
} else {
cout << "容器为空,无法弹出元素." << endl;
}
}
void insert(const value_type &x, const size_t &pos) {
if (pos > size()) {
cout << "越界: 无法在指定位置插入元素." << endl;
return;
}
if (capacity() == 0) {
reserve(1);
*_finish = x;
++_finish;
} else if (size() == capacity()) {
size_t size1 = size();
size_t cap = capacity();
value_type* tmp = new value_type[2 * capacity()]();
for (size_t i = 0; i < pos; i++) {
tmp[i] = _start[i];
}
tmp[pos] = x;
for (size_t i = pos; i < size1; i++) {
tmp[i + 1] = _start[i];
}
delete[] _start;
_start = tmp;
_finish = _start + size1 + 1;
_end = _start + 2 * cap;
} else {
for (int i = size(); i > pos; i--) {
_start[i] = _start[i - 1];
}
_start[pos] = x;
_finish = _start + size() + 1;
}
}
void erase(const size_t &pos) {
if (pos >= 0 && pos < size()) {
iterator begin = _start + pos;
while (begin != _finish) {
*begin = *(begin + 1);
++begin;
}
--_finish;
//--_end;
} else {
cout << "越界: 无法删除指定位置的元素" << endl;
}
}
void Print() {
if (empty()) {
cout << "容器为空." << endl;
return;
}
cout << "容器元素: ";
for (size_t i = 0; i < size(); i++) {
cout << _start[i] << " ";
}
cout << endl;
}
void reserve(size_t newCapacity) {
value_type* tmp = new value_type[newCapacity]();
size_t size1 = size();
if (_start) {
for (size_t i = 0; i < size1; i++) {
tmp[i] = _start[i];
}
}
delete[] _start;
_start = tmp;
_finish = _start + size1;
_end = _start + newCapacity;
}
bool empty() const {
return _start == _finish;
}
private:
iterator _start;
iterator _finish;
iterator _end;
};
BEGINS(test3)
int main() {
Vector<string> ve; //Vector<string> ve; 中的string是模板类型Vector中的元素类型
cout << "按1压入数据" << endl;
cout << "按2插入数据" << endl;
cout << "按3弹出数据" << endl;
cout << "按4删除数据" << endl;
cout << "按5查看现有数据" << endl;
cout << "按111结束" << endl;
int a, y;
string x;
while (true) {
cin >> a;
if (a == 111) break;
switch (a) {
case 1:
cout << "请输入要压入的元素: ";
cin >> x;
ve.push_back(x);
break;
case 2:
cout << "请输入要插入的元素和位置 (元素 位置): ";
cin >> x >> y;
ve.insert(x, y);
break;
case 3:
ve.pop_back();
break;
case 4:
cout << "请输入要删除的位置: ";
cin >> y;
ve.erase(y);
break;
case 5:
ve.Print();
break;
}
}
return 0;
}
ENDS(test3)
int main() {
test3::main();
return 0;
}