2.引入模版,实现模版类型的vector

在double类型vector的基础上实现vector的模版类

原文

问题:

传入模版的类型不是内建类型的情况—c++萃取机制
  • POD(Plain Old Data)类型,指的是C++的内建数据类型,还有原生指针和C风格的结构体联合体等。标准的定义是:能用C的memcpy()等函数进行操作 的类、结构体或联合体。POD类型有以下标准:
    • 没有用户自定义的构造函数、析构函数、拷贝赋值运算符;
    • 没有虚函数和虚基类;
    • 所有非静态成员都是public;
    • 所有非静态成员都是POD类型;
    • 没有继承或只继承了POD类型。
  • POD类型和复杂数据类型最大的区别是四个方面:构造(默认构造器)、析构、赋值、复制(拷贝构造器),即default_constructor,destructor,assignment_operator,copy_constructor。 复杂数据类型先天缺少这四样(编译器给它加上的不算),而可以认为POD类型是先天具备或者 根本不用考虑 这四样。
constexpr关键字
  • noexcept 是 C++11 中引入的一个关键字,用于指定函数是否可能抛出异常。在函数声明或定义时,可以使用 noexcept 关键字来指定该函数是否可能抛出异常,以便更好地管理和处理异常情况。

    具体来说,noexcept 关键字有以下几种用法:

    1. noexcept 表示函数不会抛出任何异常。

    例如:

    void foo() noexcept {
        // 函数体不会抛出异常
    }
    
    1. noexcept(true) 表示函数不会抛出任何异常。

    例如:

    void foo() noexcept(true) {
        // 函数体不会抛出异常
    }
    
    1. noexcept(false) 表示函数可能会抛出异常。

    例如:

    void foo() noexcept(false) {
        // 函数体可能会抛出异常
    }
    
    1. noexcept(expression) 表示函数的异常性取决于 expression 中的表达式。

    例如:

    void foo() noexcept(sizeof(int) == 4) {
        // 函数体可能会抛出异常,取决于 sizeof(int) 是否等于 4
    }
    

    使用 noexcept 关键字可以帮助编写更加健壮和可靠的代码,特别是在处理异常和错误情况时,可以更加精确地控制异常的传递和处理。同时,使用 noexcept 关键字还可以提高代码的执行效率,因为编译器可以根据函数是否可能抛出异常来进行优化。

new/operator new/placement new

[参考](https://blog.csdn.net/finewind/article/details/82631906)

  • start = new T[n];实际上完成了三个操作:
    • new表达式调用operatar new[]的标准库函数。该函数分配一块足够大的、原始的、未命名的内存空间以便存储特定类型的对象的数组
    • 编译运行相应的构造函数一构造这些对象,并为其传入初始值
    • 对象被分配了空间并构造完成,返回一个指向该对象的指针
  • operator new主要作用是分配内存空间,无法使用construct函数构造对象。原型:
    • void *operator new(size_t);分配一个对象
    • void *operator new[](size_t);分配一个数组
    • 分配对象后要对返回的void*进行强制类型转化
      • T* p = (T*)::operator new(n*sizeof(T));
    • 释放调用delete释放
      • void *operator delete(void*) noexcept;
      • void *operator delete[](void*)noexcept;
        • 使用 noexcept 关键字可以更加精确地控制异常的传递和处理,避免不必要的异常捕获和处理开销。
        • 使用 noexcept 关键字可以提高代码的执行效率,因为编译器可以根据函数是否可能抛出异常来进行优化。
  • placement new定位new,在一个特定的、预先分配的内存地址上构造对象。原型:
    • new(place_address) type
    • new(place_address type (initializers))
    • new(place_address) type [size]
    • new(place_address) type [size] {braced initializer list}
    • placement new对象的初始化和销毁以及内存的释放
      • new(start) T(value);
      • start->~T();
      • delete start;数组的内存释放delete[] start;

思路:

  • 对于内置数据类型
    • 来说,只需要在类前加上模版语句template<typename T>,用T替换my_vector.h中的double即可
template <typename T>
class vector
{

protected:
    // 用T* 类型表示vector的头尾和可用空间的最大值
    T *start;          // 表示当前空间的头
    T *finish;         // 表示当前使用空间的尾
    T *end_of_storage; // 表示当前可用空间的尾

    // 辅助函数,作用:用于vector空间不够时扩容
    // 可用空间为0时,申请更大的空间,并把元素都复制过去
    void allocate_and_copy()
    {
        // std::cout << "调用allocate_and_copy" << std::endl;

        int len = (capacity() != 0 ? capacity() * 2 : 1); // 以容量的2倍为规则扩容
        T *temp = new T[len];                             // 创建更大的空间,temp指向可用空间的头
        for (int i = 0; i < size(); ++i)
        {
            temp[i] = start[i];
        }
        end_of_storage = temp + len;
        finish = temp + size();

        // delete start; // 回收旧数组的头节点,实际上整个旧数组都被释放了
        delete[] start; // 回收旧数组
        start = temp;
    }

public:
    // 构造函数:这里用成员初始化列表进行初始化
    vector() : start(nullptr), finish(nullptr), end_of_storage(nullptr)
    { // 默认构造
        std::cout << "vector的默认构造" << std::endl;
    }

    // 有参构造:初始化vector的长度为n
    vector(int n)
    {

        std::cout << "vector的有参构造vector(n)" << std::endl;

        start = new T[n]; // 先创建空间
        finish = start;
        end_of_storage = start + n;
        for (int i = 0; i < n; ++i) // 初始值设为0.0
        {
            start[i] = 0.0;
        }
    }

    // 有参构造:初始化vector的长度为n,并将这些位置上的数据全部赋值为value
    vector(int n, const T &value)
    {

        std::cout << "vector的有参构造vector(n,value)" << std::endl;

        start = new T[n];   // 先创建空间
        finish = start + n; // 因为对数组的数组是从0开始存放的,start+n表示的是使用空间的下一个位置
        end_of_storage = start + n;
        for (int i = 0; i < n; ++i) // 初始值设为0
        {
            start[i] = value;
        }
    }

    // 拷贝构造
    vector(const vector &another)
    {
        std::cout << "vector的拷贝构造函数" << std::endl;

        // 创建一个新空间存放another的数据
        int len = another.size();
        start = new T[len];
        for (int i = 0; i < len; ++i)
        {
            // start[i] = *(another.begin() + i);        //const对象不能调用非const成员函数
            start[i] = another[i];
        }
        finish = start + len;
        end_of_storage = finish;
    }

    // 析构函数
    ~vector()
    {
        std::cout << "vector的析构函数" << std::endl;

        delete[] start;
    }

    // 常用接口
    /**********************首尾******************************/

    // 给出vcetor当前使用空间的起始位置
    T *begin() const
    {
        return start;
    }

    // 给出vector当前使用空间的下一个位置
    T *end() const
    {
        return finish;
    }

    // 逆序遍历时,使用空间的起始位置
    T *rbegin()
    {
        return end() - 1;
    }

    // 逆序遍历时,使用空间的结束位置
    T *rend()
    {
        return begin() - 1;
    }

    /**********************随机访问******************************/

    // vector中第一个数据
    T &front()
    {
        return *begin(); // 尽量避免直接使用和暴露成员变量,保证类的封装性
    }

    // vector中最后一个数据
    T &back()
    {
        return *(end() - 1);
    }

    T &operator[](int n) // 返回引用,便于修改
    {                    // 不考虑n越界的情况
        return *(begin() + n);
    }

    T &operator[](int n) const // 返回引用,便于修改
    {                          // 不考虑n越界的情况
        return *(begin() + n);
    }

    /**********************大小******************************/

    // 此处const的作用:
    // 一、将成员函数声明为const,表明该函数不会对对象进行修改
    // 二、可以允许在const对象上调用该函数
    // vector中当前有多少个数据
    int size() const
    {
        return finish - start;
    }

    // 容量:vector中当前最多能存放多少个数据
    int capacity() const
    {
        return int(end_of_storage - begin());
    }

    int max_size() const
    {
        return end_of_storage - start;
    }

    // vector当前是否为空
    bool empty() const
    {
        return begin() == end();
    }

    /**********************  增删改  ******************************/
    // 在vector的末尾插入一个数据
    void push_back(const T &x)
    {
        // 容器内空间不够,就扩容
        if (finish == end_of_storage)
        { // 如果长度为零,初始空间设为1
            std::cout << "capacity()的值为:" << capacity() << std::endl;
            allocate_and_copy();
        }
        *finish = x;
        //*end() = x;       //ERROR:因为end()是静态成员函数,不能修改对象
        ++finish;
    }

    // 在vector的末尾删除一个数据
    void pop_back()
    {
        --finish; // ERROR:因为end()是静态成员函数,不能修改对象
    }

    // 删除position所指向的数据
    void erase(T *position)
    {
        // 把指针后面的全部前移
        for (T *i = position; (i + 1) != end(); ++i)
        {
            *i = *(i + 1);
        }
        --finish;
    }

    // 删除从first到last这一段数据
    void erase(T *first, T *last)
    {
        int diff = last - first;
        int count = 0;                              // 计数器
        for (T *i = last; i != end(); ++i, ++count) // 如果last等于end(),就不用移动后面的数据了,直接更新finish就行
        {
            *(first + count) = *(first + diff + count); // 这里等号右边必须是first + diff,刚好是last的下一个位置,计数器从0开始遍历正好
        }
        finish = finish - diff; // 指针向前移动
    }

    // 调整vetor的容量,如果调整后的容量大于调整前,则用数据x填充空余部分;
    // 如果调整后容量小于调整前,则只保留前new_size位数据
    void resize(int new_size, const T &x)
    {
        if (new_size < size())
        {
            erase(begin() + new_size, end());
        }
        else
        {
            std::cout << "capacity()的值为:" << capacity() << std::endl;
            // 考虑需要扩容的情况
            while (new_size > capacity())
            { // 数组是从0开始存储的,所以如果new_size = capacity()的情况刚好能存放

                allocate_and_copy();
                std::cout << "capacity()的值为:" << capacity() << std::endl;
            }
            for (int i = 0; i < new_size - size(); ++i)
            {
                *(finish + i) = x;
            }
            finish += new_size - size();
        }
    }

    // 调整后的容量大于调整前,则用默认数据填充空余部分,其余上同
    void resize(int new_size)
    {
        resize(new_size, 0.0);
    }

    // 清空vector中所有数据
    void clear()
    {
        erase(begin(), end());
    }
};

vector类的全部源码

template<class T, class Alloc=alloc>        //alloc直接调用第二级空间配置器,当要分配的内存大于128kb时,调用第一级配置器
class vector {
public:
    /**                       vector的嵌套类型定义                        **/
    typedef T value_type;
    typedef value_type *pointer;
    typedef value_type *iterator;           //定义vector类的迭代器
    typedef const value_type *const_iterator;
    typedef value_type &reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;


    typedef const value_type *const_pointer;
    typedef const value_type &const_reference;


protected:
    /**                        设置空间配置器                              **/
    //这个是空间配置器的API
    typedef simple_alloc<value_type, Alloc> data_allocator;             //确定了分配空间的类型

    //定义迭代器
    iterator start;             //表示目前使用的空间的头
    iterator finish;            //表示目前使用的空间的尾
    iterator end_of_storage;     //表示目前可用空间的尾


    //配置空间并填满内容
    iterator allocate_and_copy(const_iterator first, const_iterator last, iterator result) {
        size_type len = size_type(last - first);
        result = data_allocator::allocate(len);
        uninitialized_copy(first, last, result);
        return result;
    }


    iterator allocate_and_fill(size_type n, const_reference x) {
        iterator result = data_allocator::allocate(n);    //先分配空间,已知分配空间的类型,只需传递要分配的个数即可
        uninitialized_fill_n(result, n, x);
        return result;
    }

    void insert_aux(iterator position, const_reference x);

    //销毁容器所占的空间
    void deallocate() {
        if (start) {
            data_allocator::deallocate(start, end_of_storage - start);
        }
    }

    void fill_initialize(size_type n, const_reference value) {
        start = allocate_and_fill(n, value);
        finish = start + n;
        end_of_storage = finish;
    }

    void copy_initialize(const vector<T, Alloc> &value) {
        start = allocate_and_copy(value.begin(), value.end(), start);
        finish = start + value.size();
        end_of_storage = finish;
    }

public:

    /**                         构造                    **/
    //默认构造
    vector() : start(nullptr), finish(nullptr), end_of_storage(nullptr) {

    }

    //有参构造,会调用T类型的默认构造
    explicit vector(size_type n) {          //explicit是一个C++关键字,用于修饰构造函数,指示编译器不要对 参数 自动执行隐式类型转换
        fill_initialize(n, value_type());
    }

    vector(size_type n, const_reference value) {
        fill_initialize(n, value);
    }

    vector(int n, const_reference value) {
        fill_initialize(n, value);
    }

    vector(long n, const_reference value) {
        fill_initialize(n, value);
    }

    vector(const value_type *first, const value_type *last) {
        start = allocate_and_copy(first, last, start);
        finish = start + (last - first);
        end_of_storage = finish;
    }


    /**                         拷贝构造                    **/
    vector(const vector<T, Alloc> &value) {
        copy_initialize(value);
    }


    /**                         析构                    **/
    ~vector() {
        destroy(start, finish);
        deallocate();           //释放空间
    }
    /**                         常用接口                    **/
    /**                         首尾                    **/
    iterator begin() { return start; }

    const_iterator begin() const { return start; }

    iterator end() { return finish; }

    const_iterator end() const { return finish; }

    reference front() { return *begin(); }

    const_reference front() const { return *begin(); }

    reference back() { return *(end() - 1); }

    const_reference back() const { return *(end() - 1); }

    /**                         大小                    **/
    //容量
    size_type capacity() const { return end_of_storage - begin(); }

    size_type size() const { return size_type(end() - begin()); }

    bool empty() const { return begin() == end(); }


    /**                         增删改查                    **/
    //随机访问
    reference operator[](size_type n) {
        return *(begin() + n);
    }

    const_reference operator[](size_type n) const {
        return *(begin() + n);
    }

    //增
    //从position开始,插入n个元素
    //返回的是新插入元素的第一个
    iterator insert(iterator position, const_reference x) {
        size_type n = position - begin();
        if (finish != end_of_storage && position == end()) {
            construct(finish, x);
            ++finish;
        } else {
            insert_aux(position, x);
        }
        //return position;      //当position是end()可能出错
        return begin() + n;
    }

    iterator insert(iterator position, size_type n, const_reference x);

    void insert(iterator position, const_iterator first, const_iterator last);

    void push_back(const_reference value) {
        if (finish != end_of_storage) {
            construct(finish, value);
            ++finish;
        } else {
            insert_aux(end(), value);
        }
    }

    //删
    void pop_back() {
        --finish;
        destroy(finish);
    }

    //返回指向被删除元素之后的第一个元素的迭代器,方便在删除一个或多个元素后,遍历容器中的剩余元素
    iterator erase(iterator position) {      //清除某个位置上的元素
        if (position + 1 != end()) {
            //如果position指的不是最后一个对象,需要把后面的全部向前移动一个位置
            uninitialized_copy(position + 1, finish, position);
        }
        --finish;
        destroy(finish);
        return position;
    }

    //这里的移除是左闭右开
    iterator erase(iterator first, iterator last) {
        //这里要不要考虑last越界的问题
        //这个复制是左闭右开的
        iterator temp = uninitialized_copy(last, finish, first);
        destroy(temp, finish);
        finish = finish - (last - first);
        return first;
    }

    void resize(size_type new_size, const_reference x) {
        if (new_size < size()) {
            erase(begin() + new_size, end());
        } else
            insert(end(), new_size - size(), x);
    }

    void resize(size_type new_size) {
        resize(new_size, value_type());
    }

    void clear() {
        erase(begin(), end());
    }


};

template<class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const_reference x) {
    if (finish != end_of_storage) {         //这是随机插入用的
        construct(finish, *(finish - 1));

        ++finish;
        T x_copy = x;
        copy_backward(position, finish - 2, finish - 1);
        *position = x_copy;
    } else {   //这个是push_back用的
        const size_type old_size = size();
        const size_type len = old_size != 0 ? old_size * 2 : 1;

        iterator new_start = data_allocator::allocate(len);
        iterator new_finish = new_start;

        //把旧容器的对象都复制到新分配的空间
        try {
            new_finish = uninitialized_copy(start, position, new_start);
            construct(new_finish, x);    //把对象x插入新分配的空间
            ++new_finish;
            new_finish = uninitialized_copy(position, finish, new_finish);    //这行代码在push_back中没用,应该是在insert中使用的
        }
        catch (...) {       //错误处理
            destroy(new_start, new_finish);
            data_allocator::deallocate(new_start, len);
            throw;
        }

        //析构并释放原vector
        destroy(begin(), end());
        deallocate();

        //调整迭代器,指向新vector
        start = new_start;
        finish = new_finish;
        end_of_storage = new_start + len;
    }
}

//从position开始,插入n个元素x
template<class T, class Alloc>
typename vector<T, Alloc>::iterator vector<T, Alloc>::insert(iterator position, size_type n, const_reference x) {
    if (n != 0) {     //先判断插入元素个数的合法性
        if (size_type(capacity() - size()) >= n) {      //再判断当然剩余空间是否满足n个元素的空间需求
            value_type x_copy = x;
            const size_type elems_after = end() - position;
//            const size_type elems_after = distance(position, end());
            iterator old_finish = finish;
            if (elems_after > n) {      //插入点之后的现有元素个数大于新增元素个数
//                uninitialized_copy(position, finish, position + n);  不能这么搞,在从前往后复制的过程中会覆盖掉原来的元素导致出错
                uninitialized_copy(finish - n, finish, finish);     //把finish之前的n个元素移动到finish之后
                finish = old_finish + n;                            //更新finish
                copy_backward(position, old_finish - n,
                              old_finish);                 //再把position到old_finish-n范围内的元素从后往前依次复制到old_finish范围内
                fill(position, position + n, x_copy);   //把填充到position,positon +n范围内,
                /*这样做的好处是移动现有元素的过程中不会相互覆盖*/
            } else {
                //插入点之后的现有元素个数小于等于先增元素个数
                uninitialized_fill_n(finish, n - elems_after, x_copy);      //先把大于elems的个数插入到finish之后
                finish = finish + n - elems_after;                                      //更新finish
                uninitialized_copy(position, old_finish,
                                   finish);                       //再把position,finish范围内的元素填充到容器尾部
                finish += elems_after;                                                  //更新finish
                uninitialized_fill(position, old_finish, x_copy);           //最后把x填充到position,old-finish中

            }
        } else {
            //备用空间小于"新增元素个数",需要配置额外的内存
            //首先决定新长度:旧长度的两倍或者旧长度+新增元素的个数
            const size_type old_size = size();
            const size_type len = old_size + max(old_size, n);
            iterator new_start = data_allocator::allocate(len);
            iterator new_finish = new_start;
            try {
                //以下首先将旧vector的插入点之前的元素复制到新空间
                new_finish = uninitialized_copy(start, position, new_start);
                //把要插入的元素插入新分配的空间
                new_finish = uninitialized_fill_n(new_finish, n, x);
                //把插入点之后的元素插入新空间
                new_finish = uninitialized_copy(position, finish, new_finish);
            }
//#ifdef __STL_USE_EXCEPTIONS
            catch (...) {
                //如果有异常发生,就销毁新分配的空间并报错
                destroy(new_start, new_finish);
                data_allocator::deallocate(new_start, len);
                throw;
            }
//#endif
            //以下是清除并释放旧的vector
            destroy(start, finish);
            deallocate();

            start = new_start;
            finish = new_finish;
            end_of_storage = new_finish + len;
            return position;
        }
    }

}


template<class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, const_iterator first, const_iterator last) {
    if (first != last) {
        size_type n = 0;
        n = distance(first, last);               //在stl_iterator.h中
        if (size_type(end_of_storage - finish) >= n) {
            const size_type elems_after = finish - position;
            iterator old_finish;
            if (elems_after > n) {
                uninitialized_copy(finish - n, finish, finish);
                finish = finish + n;
                copy_backward(position, old_finish - n, old_finish);
                copy(first, last, position);
            } else {
                uninitialized_copy(first + elems_after, last, finish);
                finish = finish + n - elems_after;
                uninitialized_copy(position, old_finish, finish);
                finish += elems_after;
                copy(first, first + n, position);
            }
        } else {
            const size_type old_size = size();
            const size_type len = old_size + max(old_size, n);
            iterator new_start = data_allocator::allocate(len);
            iterator new_finish = new_start;

            try {
                new_finish = uninitialized_copy(start, position, new_start);
                new_finish = uninitialized_copy(first, last, new_finish);
                new_finish = uninitialized_copy(position, finish, new_finish);
            }
            catch (...) {
                destroy(new_start, new_finish);
                data_allocator::deallocate(new_start, len);
                throw;
            }
            destroy(start, finish);
            deallocate();

            start = new_start;
            finish = new_finish;
            end_of_storage = start + len;
        }

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值