一、实现时需要注意的关键方面

1. 模板与类型定义
模板类应该是一个类模板:template<typename T>
提供标准类型定义:value_type, iterator, const_iterator 等,用于与 STL 算法兼容。

2. 内存管理
使用 new / delete 或 allocator<T> 管理内存。
避免内存泄漏:确保所有内存都被正确释放(尤其是在异常处理时)。
实现 Rule of Five(拷贝构造、拷贝赋值、移动构造、移动赋值、析构)。

3. 异常安全性
所有操作(如 push_back)必须提供强异常保证或基本异常保证。
std::allocator 提供构造、销毁元素的方法,可用于安全构造对象。

4. 迭代器兼容性
提供 begin()、end() 返回迭代器。
迭代器应至少支持 STL 输入迭代器(可以直接用裸指针 T* 作为迭代器)。

5. 与 STL 算法兼容
类型别名如 value_type, reference, const_reference 可用于 STL 算法模板匹配。
重载操作符(如 operator[])与标准容器行为一致。

6. 性能优化
push_back 和 reallocate 时应该采用几何扩展策略(例如容量每次乘以 2)。
使用 std::move 移动元素,减少复制开销。

注:
value_type 表示“容器里元素的类型”。

std::vector<int> t;
std::vector<int>::value_type x = 42;
🔄 它的作用是?

主要是为 模板泛型算法 和 容器无关的编程 提供一种统一访问元素类型的方式。

例子:写一个函数模板接受任何容器
template<typename Container>
void printFirst(const Container& c) {
    typename Container::value_type val = *c.begin();
    std::cout << val << std::endl;
}


无论传入的是 std::vector<int> 还是 std::list<std::string>,value_type 都能正确推导出元素类型。

reference
reference 表示“容器中元素的引用类型”,通常是 T&,用于读写元素。

template <typename Container>
void setFirstElement(Container& c, const typename Container::value_type& newValue) {
    typename Container::reference ref = c.front();  // T& 类型
    ref = newValue;  // 修改第一个元素
}

二、实现代码:

template<typename T>
class MyVector {
public:
    // 类型定义
    using value_type = T;
    using iterator = T*;
    using const_iterator = const T*;

    // 构造函数、析构函数
    MyVector();
    MyVector(size_t size);
    ~MyVector();

    // 拷贝/移动 构造与赋值运算符
    MyVector(const MyVector& other);
    MyVector& operator=(const MyVector& other);
    MyVector(MyVector&& other) noexcept;
    MyVector& operator=(MyVector&& other) noexcept;

    // 容器接口
    void push_back(const T& value);
    void pop_back();
    T& operator[](size_t index);
    const T& operator[](size_t index) const;
    size_t size() const;
    bool empty() const;

    // 迭代器支持
    iterator begin();
    iterator end();
    const_iterator begin() const;
    const_iterator end() const;

private:
    T* data_;
    size_t size_;
    size_t capacity_;

    void reallocate(size_t new_capacity);
};

MyVector(const MyVector& other) 和MyVector(MyVector&& other) noexcept有什么区别,other不都是传进来的引用吗,都是不拷贝一份?

const MyVector& other只是不拷贝一份形参,但实现内容会深拷贝一份返回给新对象,且不能修改原值 MyVector&&
other 是可以修改原值的 因此它可以将原值修改为空,并且接管原值指向的内存

#include <cstddef>   // for size_t
#include <stdexcept> // for exceptions
#include <utility>   // for std::move
#include <algorithm> // for std::copy

template<typename T>
class MyVector {
public:
    using value_type = T;
    using iterator = T*;
    using const_iterator = const T*;

    // 默认构造函数
    MyVector()
            : data_(nullptr), size_(0), capacity_(0) {}

    // 有参数构造函数
    MyVector(size_t size)
            : data_(new T[size]), size_(size), capacity_(size) {}

    // 析构函数
    ~MyVector() {
        delete[] data_;
    }

    // 拷贝构造函数(深拷贝)
    MyVector(const MyVector& other)
            : data_(new T[other.capacity_]), size_(other.size_), capacity_(other.capacity_) {
        std::copy(other.data_, other.data_ + other.size_, data_);
    }

    // 拷贝赋值运算符(深拷贝)
    MyVector& operator=(const MyVector& other) {
        if (this != &other) {
            delete[] data_;
            data_ = new T[other.capacity_];
            size_ = other.size_;
            capacity_ = other.capacity_;
            std::copy(other.data_, other.data_ + other.size_, data_);
        }
        return *this;
    }

    // 移动构造函数
    MyVector(MyVector&& other) noexcept
            : data_(other.data_), size_(other.size_), capacity_(other.capacity_) {
        other.data_ = nullptr;
        other.size_ = 0;
        other.capacity_ = 0;
    }

    // 移动赋值运算符
    MyVector& operator=(MyVector&& other) noexcept {
        if (this != &other) {
            delete[] data_;
            data_ = other.data_;
            size_ = other.size_;
            capacity_ = other.capacity_;
            other.data_ = nullptr;
            other.size_ = 0;
            other.capacity_ = 0;
        }
        return *this;
    }

    // 添加元素
    void push_back(const T& value) {
        if (size_ >= capacity_) {
            reallocate(capacity_ == 0 ? 1 : capacity_ * 2);
        }

        try {
            data_[size_] = value;
            ++size_;
        } catch (...) {
            // 如果赋值失败,size_ 不增加
            throw;
        }
    }


    // 删除最后一个元素
    void pop_back() {
        if (size_ == 0) throw std::out_of_range("Vector is empty");
        --size_;
    }

    // 下标访问
    T& operator[](size_t index) {
        if (index >= size_) throw std::out_of_range("Index out of range");
        return data_[index];
    }

    const T& operator[](size_t index) const {
        if (index >= size_) throw std::out_of_range("Index out of range");
        return data_[index];
    }

    // 当前元素数量
    size_t size() const {
        return size_;
    }

    // 是否为空
    bool empty() const {
        return size_ == 0;
    }

    // 迭代器
    iterator begin() { return data_; }
    iterator end() { return data_ + size_; }

    const_iterator begin() const { return data_; }
    const_iterator end() const { return data_ + size_; }

private:
    T* data_;
    size_t size_;
    size_t capacity_;

    // 内部扩容函数
    void reallocate(size_t new_capacity) {
        // 先分配新内存
        T* new_data = new T[new_capacity];

        size_t i = 0;
        try {
            // 尝试移动构造所有已有元素
            for (; i < size_; ++i) {
                new_data[i] = std::move(data_[i]);
            }
        } catch (...) {
            // 如果中途抛异常,需要销毁已构造对象并释放内存
            delete[] new_data;
            throw;  // 重新抛出异常
        }

        // 一切安全完成后再替换旧数据
        delete[] data_;
        data_ = new_data;
        capacity_ = new_capacity;
    }

};

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐