实现一个简化版的动态数组

我们将实现一个简化版的 std::vector,这个容器能够动态地存储任何类型的元素,并支持在元素数量增加时自动扩容。通过模板,我们能做到类型无关,也就是说,无论是存储 intdouble,还是自定义类型 Test 的对象,都能使用这个容器。

#include <iostream>
#include <stdexcept>  // 用于异常处理

// 定义一个模板类 SimpleVector,支持任何类型的元素
template <typename T>
class SimpleVector {
private:
    T* data;         // 数据存储的原始指针
    size_t size;     // 当前容器的元素个数
    size_t capacity; // 当前容器分配的容量

    // 扩容函数:当容器满时自动扩展容量
    void resize(size_t new_capacity) {
        // 创建一个新的内存区域,大小为 new_capacity
        T* new_data = new T[new_capacity];
        
        // 将原有的数据拷贝到新的内存区域
        for (size_t i = 0; i < size; ++i) {
            new_data[i] = data[i];  // 拷贝每个元素
        }
        
        // 释放原先的内存
        delete[] data;
        
        // 更新指针和容量
        data = new_data;
        capacity = new_capacity;
    }

public:
    // 构造函数:初始化容量为0
    SimpleVector() : data(nullptr), size(0), capacity(0) {}

    // 析构函数:在对象销毁时释放内存
    ~SimpleVector() {
        delete[] data;  // 自动释放内存
    }

    // 添加元素到容器末尾
    void push_back(const T& value) {
        // 如果当前元素数达到了容量,则扩容
        if (size == capacity) {
            resize(capacity == 0 ? 1 : capacity * 2);  // 扩展容量:0时初始化为1,否则翻倍
        }
        
        // 将新元素放入容器末尾
        data[size++] = value;
    }

    // 获取指定索引的元素
    T& operator[](size_t index) {
        // 检查索引是否合法
        if (index >= size) {
            throw std::out_of_range("Index out of bounds");  // 超出边界抛出异常
        }
        return data[index];
    }

    // 获取当前容器中元素的个数
    size_t get_size() const {
        return size;
    }

    // 判断容器是否为空
    bool is_empty() const {
        return size == 0;
    }
};

class Test {
public:
    Test() {
        std::cout << "Test object created." << std::endl;
    }

    ~Test() {
        std::cout << "Test object destroyed." << std::endl;
    }

    void hello() {
        std::cout << "Hello, I'm a Test object!" << std::endl;
    }
};

int main() {
    SimpleVector<int> vec;  // 创建一个 SimpleVector 容器,存储整数类型的元素
    vec.push_back(10);  // 添加元素 10
    vec.push_back(20);  // 添加元素 20
    vec.push_back(30);  // 添加元素 30

    std::cout << "Size of vector: " << vec.get_size() << std::endl;  // 输出容器的当前大小

    // 输出容器中的所有元素
    for (size_t i = 0; i < vec.get_size(); ++i) {
        std::cout << "Element " << i << ": " << vec[i] << std::endl;
    }

    std::cout << "End of scope." << std::endl;  // 程序结束时会自动释放内存

    return 0;
}
1. SimpleVector 类模板

我们使用了模板类 SimpleVector,通过 template <typename T> 声明,允许 SimpleVector 管理任何类型的数据。T 是我们传递给模板的类型,它可以是 intdouble,甚至是自定义类型。

私有成员:
  • T* data: 存储元素的指针,实际上是动态分配的一块内存区域。
  • size_t size: 当前容器中实际存储的元素数量。
  • size_t capacity: 容器的总容量,即分配的内存空间大小。
resize() 方法:

当我们向 SimpleVector 添加新元素时,如果当前容量不足,它会调用 resize() 扩展内存:

  • 内存扩展:我们新分配一块更大的内存,并将原有的数据复制到新区域。
  • 内存释放:原来的内存空间通过 delete[] 释放,防止内存泄漏。
push_back() 方法:

我们用 push_back() 向容器中添加元素。每次添加元素时,如果当前容量已满,它会调用 resize() 方法自动扩容。

2. 析构函数 ~SimpleVector()

SimpleVector 对象销毁时,析构函数会被自动调用,它负责释放 data 指向的内存区域。因为我们使用的是动态分配的内存,所以必须显式地进行释放,防止内存泄漏。

3. 访问元素:

我们通过重载 operator[] 来让用户像使用普通数组一样访问容器中的元素。为了避免越界访问,我们添加了一个边界检查。如果访问的索引超出了当前元素的范围,会抛出 std::out_of_range 异常。

4. 主函数 main()
  • 我们创建了一个存储 int 类型的 SimpleVector 容器,向其中添加了三个元素:10、20 和 30。
  • vec.push_back(10) 会将 10 添加到容器的末尾,依此类推,直到添加完所有元素。
  • 使用 vec.get_size() 获取容器的大小。
  • 最后,使用循环访问容器中的每个元素,并输出。

内存管理:

  • 自动扩容:当容器满时,我们自动扩展内存。resize() 方法确保新元素能顺利添加,而不需要用户手动管理内存。
  • 内存释放:析构函数 ~SimpleVector() 会在容器对象销毁时释放所有动态分配的内存,避免了内存泄漏。

优势与扩展:

  1. 通用性:通过模板,我们的容器不仅限于 int 类型,还可以管理任何类型的数据。
  2. 动态扩容:容器会根据需要自动扩展大小,避免了数组大小固定的限制。
  3. 内存安全:使用 delete[] 确保释放动态分配的内存,避免了内存泄漏。
  4. 功能扩展:你可以继续扩展 SimpleVector,添加更多功能,比如删除元素、清空容器、支持迭代器等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值