深入理解C++ Vector类的实现,简单详细(附源码)

深入理解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;
};
  1. Vector 是一个模板类,使用 T 表示元素的类型。
  2. value_type 定义了元素的类型,iterator 定义了迭代器类型。
  3. _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;
}
  1. push_back 将元素添加到容器的末尾。
  2. 如果容器的容量为零或者容量已满,调用 reserve 函数进行扩容。
  3. 将元素添加到 _finish 指向的位置,然后将 _finish 向后移动。

pop_back 函数

void pop_back() {
    if (!empty()) {
        --_finish;
        std::cout << "弹出元素: " << *_finish << std::endl;
    } else {
        std::cout << "容器为空,无法弹出元素." << std::endl;
    }
}
  1. pop_back 从容器末尾弹出一个元素。
  2. 如果容器不为空,将 _finish 向前移动一个位置,并打印弹出的元素。
  3. 如果容器为空,输出一条相应的提示信息。

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;
}
  1. reserve 函数用于预留足够的容量,以便存储指定数量的元素。
  2. 创建一个新的数组 tmp,将原有元素复制到新数组。
  3. 释放原有内存,将 _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;
        }
}
  1. insert 函数用于在指定位置插入元素。
  2. 如果插入位置超出当前元素个数,输出提示信息并返回。

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;
    }
}
  1. erase 函数用于删除指定位置的元素。
  2. 如果位置合法,从指定位置开始,将后续元素向前移动一个位置。
  3. 更新 _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;
}
  • 12
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【资源说明】 基于C++实现的HTTP服务器改进版源码+项目使用说明+详细注释.zip 1、技术架构 **本项目实现了基于Epoll管理连接、基于定时器处理非活动连接、基于线程池实现Reactor模式、基于cgi脚本处理http请求结果的HTTP服务器。主要框架如下:**\ ![](./image/newhttpd.jpg) 2、模块介绍 **1)主线程实现eventLoop**:主线程基于Reactor并通过Epoll管理,采用ET工作模式进行事件触发,事件注册包括监听、管道监控、读信息监控;\ **2)定时器处理非活动连接**:\ **①基于升序链表的定时器**:将每个需要监控的连接注册为一个时间结点,每个结点包括双向指针以及期待的时间和回调函数指针;包含添加、删除以及调整结点;回调函数主要实现对当前连接的close;\ **②基于信号和管道的定时事件处理**:建立监听数据集(新连接会加入一个数据集和时间结点,新信息读入会读取数据集并修改时间结点),基于sigaction形式实现对信号和信号处理函数的绑定,信号处理函数向管道发送信号消息,主线程监听到管道消息读入后判断信号别,并进行关闭连接操作。\ **3)Http响应处理**:基于tinyhttpd进行修改,捕获GET、POST方法,基于cgi脚本(python撰写)实现post请求响应,基于多进程机制并通过双通道实现进程间通信,并用waitpid进行子进程管控。具体结构如下图所示:\ ![](./image/httpd.jpg) \ **4)线程池**:基于C++的生产者消费者模式的并发开发,具体技术运用如下:\ **①线程池底层结构**:线程池创建相当于消费者,队列添加相当于生产者,通过vector维护线程池,通过queue<function<>>维护任务队列;构造函数实现线程池创建并开始运行,enqueue函数实现消息队列,通过future实现异步工作的lambda函数的传递;\ **②同步机制实现**:基于unique_lock以及condition_variable实现同步和互斥,符合RAII原则;\ **5)简单客户端**:(可以通过浏览器进行服务端访问,也可以通过该客户端实现交互以及非活动连接处理的测试)\ **①基于POLL的IO复用**:对管道和连接进行事件监听和处理;\ **②基于双管道的简易CGI实现**:修改stdin的定向为管道写端,实现终端对客户端的直接输入和对服务端的发送;\ **6)改进方向**:待进行压力测试并提高抗压性能、可处理的HTTP请求较为简单(数据体的处理还待增加以及CGI功能的完善)、内存池。 3、编译使用 **服务端**:进入linux系统后,进入当前文件夹,首先修改可执行权限,然后通过CMake编译执行即可: ~~~c cd minghttp chmod 600 test.html chmod 600 post.html chmod +X post.cgi cd .. cmake . make ./httpserver ~~~ **客户端**:一方面可以通过浏览器直接进行服务器访问,一方面可以使用自己创建的客户端进行连接和消息互传(使用方案如下): ~~~c g++ simclient.cpp ./a.out ip port ~~~ ![](./image/out.jpg) 4、呈现效果 上一部分的图片已经展现定时器处理非活动连接的效果;\ 1)项目默认端口号为8000,ip地址需要通过ifconfig进行查看;\ 2)将ip和端口号进行替换输入,如下输入后可以得到如下界面:\ ![](./image/test.jpg)\ 3)POST的界面信息:\ ![](./image/jie.jpg)\ 4)POST的CGI脚本回显,基于python进行撰写,内容传输为html语言:\ ![](./image/cgi.jpg)\ 5)定时器的相关讯息也可以得到:可以看到5秒信号的定时器信息输出:\ ![](./image/jie1.jpg) 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值