STL容器之vector

一、简单认识vector

​ 1.vector是一种有序顺序表模板;2.vector插入或者删除都存在迭代器失效问题;

​ 与string的区别:

​ 1.相较于string的设计简单了不少,且vector是一个模板;2.vector<char>并不能替代string,因为string有’\0’结尾,自动实现,而vector可以’\0’结尾,但不能自动实现;3.string的接口更加丰富,如:+=,比较大小的设计更有意义,find等字符函数的用途;

template < class T, class Alloc = allocator<T> > class vector; // generic template

​ stl的所有容器都使用了空间配置器(内存池),

二、vector的使用

1.成员类型在这里插入图片描述

2.默认成员函数

2.1构造函数

//1.无参
explicit vector (const allocator_type& alloc = allocator_type());
//2.n个T类型的值
explicit vector (size_type n, const value_type& val = value_type(),const allocator_type& alloc = allocator_type());
//3.用迭代器模板初始化,函数模板隐式实例化。可以使用自己类型的迭代器,也可以使用其他类型的。
//因为指针是天然的迭代器,所以也支持。
template <class InputIterator>
vector (InputIterator first, InputIterator last,const allocator_type& alloc = allocator_type());

3.迭代器

​ 与string一样。

iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;

4.堆空间操作

//1
size_type size() const;
//2
void resize (size_type n, value_type val = value_type());
//3
void reserve (size_type n);
void test()
{
    vector<int> v;
    //v.reserve(10 * sizeof(int));//使用reserve主要是一次性开部分空间,为了减少扩容消耗。
   	v.resize(10);//这样就size不为零。
    for (size_t i = 0; i < 10; ++i)
    {
        v[i] = i;//operato[]r会使用断言,检查pos位置是否小于size。size为0,一定报错。at是抛异常。
    }
}

5.元素访问

//1
reference operator[] (size_type n);
const_reference operator[] (size_type n) const;
//2
reference at (size_type n);
const_reference at (size_type n) const;
//3
reference front();
const_reference front() const;
//4
reference back();
const_reference back() const;
//5
value_type* data() noexcept;
const value_type* data() const noexcept;

6.修改数据

//1.尾插
void push_back (const value_type& val);
//2.尾删
void pop_back();
//3.任意位置插入
iterator insert (iterator position, const value_type& val);//迭代器位置往后一个值
void insert (iterator position, size_type n, const value_type& val);//迭代器往后n个值
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);
//4.任意位置删除
//设计迭代器失效的问题
iterator erase (iterator position);//删除某个位置
iterator erase (iterator first, iterator last);//删除某段区间
//5.swap
void swap (vector& x);
//6.清理数据
void clear()
//7.重新赋值
template <class InputIterator>
void assign (InputIterator first, InputIterator last);
void assign (size_type n, const value_type& val);

三、算法algorithm

​ 使用迭代器实现不同容器的复用。

#include<algorithm>
//1.sort
template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);
//2.swap
template <class T> void swap (T& a, T& b);
//3.find
template <class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val);
An iterator to the first element in the range that compares equal to val.
If no elements match, the function returns last.

补充:1.对于指针变量来说,指针变量存放的是地址,使用解引用底层会到存放的地址处进行访问,对于空指针和野指针,进行访问就会导致程序崩溃。2.一级指针变量的地址被设置成了只能存放在二级指针变量的空间。3.对于获得使用权的空间,使用的是不同的类型来划定空间的范围来进行访问,如:int*的指针变量,每次可访问4个字节,对它的++就被识别成了按照4个字节进行移动。

四、vector的模拟实现

补充:

​ 1.c++初始化列表出现以后对内置类型进行了升级,支持了默认构造;2.注意扩容逻辑对于自定义类型不能使用浅拷贝memcpy,可以使用赋值运算符重载;3.插入删除时会存在迭代器失效问题,所以没吃都要重置迭代器;4.对于拷贝构造和赋值重载可以复用resize和reserve,使用前必须在初始化列表进行初始化,底层会实现对成员变量的修改,要注意的是reserve后要clear数据,然后必须用尾插,resize直接使用赋值,或者clear之后尾插;5.reserve还有finish_没有初始化,resize全部初始化了;6.使用迭代器区间构造,类模板里面定义函数模板。

1.成员变量

public:
    typedef T value_type;
	typedef value_type* iterator;
protected:
  	iterator start;
  	iterator finish;
  	iterator end_of_storage;
//并不是以下的,所以需要了解一下构造函数和插入接口或者扩容逻辑
	iterator a_;
	size_t size_;
	size_t capacity;

2.默认成员函数

//1.默认构造
//1.1
vector() : start_(nullptr), finish_(nullptr), end_of_storage_(nullptr) {}
//1.2
vector(size_t n, const T &val = T()) : start_(nullptr), finish_(nullptr), end_of_storage_(nullptr)
{
    resize(n, val);
}
//1.3
template <class InputIteartor>//可能会和1.2冲突,vector<int>v(10u,5),才会识别成1.2
vector(InputIteartor first, InputIteartor last): start_(nullptr), finish_(nullptr), end_of_storage_(nullptr)
{
    while (first != last)
    {
        push_back(*first);
        first++;
    }
}
//2.拷贝构造
//2.1传统方式
vector(const vector<T> &v) : start_(nullptr), finish_(nullptr), end_of_storage_(nullptr)
{
    start_ = new T[v.capacity()];
    for (size_t i = 0; i < v.size(); i++)
    {
        start_[i] = v.start_[i];
    }
    finish_ = start_ + v.size();
    end_of_storage_ = start_ + v.capacity();
}
//2.2复用reserve,resize
vector(const vector<T> &v) : start_(nullptr), finish_(nullptr), end_of_storage_(nullptr)
{
    // reserve(v.capacity());
    // for (auto e : v)
    // {
    //     push_back(e);
    // }
    resize(v.size());
    for (size_t i = 0; i < v.size(); i++)
    {
        start_[i] = v.start_[i];
    }

}
//2.3现代方式
//3赋值重载
//3.1复用resize reserve
vector<T> &operator=(const vector<T> &v)
{
    resize(v.size());//成员变量全部初始化好
    for (size_t i = 0; i < v.size(); i++)
    {
        start_[i] = v.start_[i];//转换为调用自定义类型的赋值运算符重载
    }
    return *this;
    reserve(v.capacity());//finish_没初始化
    clear();
    for (auto e : v)
    {
        push_back(e);//会初始化finish_
    }
    return *this;
}
//3.2现代方式
vector<T> &operator=(vector<T> v)
{
    std::swap(start_, v.start_);
    std::swap(finish_, v.finish_);
    std::swap(end_of_storage_, v.end_of_storage_);
    return *this;
}
//3.3传统方式
vector<T> &operator=(const vector<T> &v)
{
    reserve(v.capacity());
    clear();
    //memcpy(start_, v.start_, sizeof(T) * v.size());//对于自定义类型memcpy会浅拷贝,会产生野指针问题,和内存泄漏。
    for (auto e:v)
    {
        push_back(e);
    }
    return *this;
}
~vector()
{
    if (start_)
    {
        delete[] start_;
        start_ = finish_ = end_of_storage_ = nullptr;
    }
}

3.插入接口

void push_back(const T &val)
{
    // if (finish_ == end_of_storage_)
    // {
    //     size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
    //     reserve(newcapacity);
    // }
    // *finish_ = val;
    // ++finish_;
    insert(end(), val);
}
// 注意迭代器失效的问题:1.野指针失效,内外迭代器都会因为异地扩容释放旧空间,导致pos失效了。
iterator insert(iterator pos, const T &val)
{
    assert(pos >= start_ && pos <= finish_);
    if (finish_ == end_of_storage_)
    {
        size_t len = pos - start_;
        size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newcapacity);
        pos = start_ + len;
    }
    iterator end = finish_ - 1;
    while (end >= pos)
    {
        *(end + 1) = *end;
        end--;
    }
    *pos = val;
    finish_++;
    return pos;
}

4.删除接口

//迭代器失效,最后一个位置的数据一般都不会挪动,再次访问最后一个位置就会出现问题。
//vs对迭代器进行了强制检查,访问程序直接就崩了;g++没有强制检查。
//为具有平台移植性,对于失效的迭代器不能访问。
iterator erase(iterator pos)
{
    assert(pos >= start_ && pos < finish_);
    iterator it = pos + 1;
    while (it < finish_)
    {
        *(it - 1) = *it;
        ++it;
    }
    --finish_;
    return pos;
}
void pop_back()
{
    erase(end() - 1);
}

5.对于空间的操作

size_t capacity() const
{
    return end_of_storage_ - start_;
}
size_t size() const
{
    return finish_ - start_;
}
//对于自定义类型要注意memcpy会浅拷贝,如:vector<string>在扩容时使用了memcpy,
//对sting对象进行了浅拷贝
void reserve(size_t n)
{
    if (n > capacity())
    {
        size_t oldsize = size();
        iterator tmp = new T[n];
        if (start_)
        {
            // memcpy(tmp, start_, oldsize * sizeof(T));//扩容可能浅拷贝
            for (size_t i = 0; i < oldsize; i++)
            {
                tmp[i] = start_[i];
            }
            delete[] start_;
        }
        // 问题
        //  start_ = tmp;
        //  finish_ = start_ + size(); // 调用size时,函数内的start_已经变了,不是0。
        //  end_of_storage_ = start_ + n;
        // 解决1
        //  finish_ = tmp + size();
        //  start_ = tmp;
        //  end_of_storage_ = start_ + n;
        // 解决2
        start_ = tmp;
        finish_ = start_ + oldsize;
        end_of_storage_ = start_ + n;
    }
}
bool empty()
{
    return size() == 0;
}
void resize(size_t n, const T &x = T())
{
    if (n < size())
    {
        finish_ = start_ + n;
    }
    else
    {
        reserve(n);
        while (finish_ != start_ + n)
        {
            *finish_ = x;
            ++finish_;
        }
    }
}
void clear()
{
    resize(0);
}

6.元素访问

T &operator[](size_t pos)
{
    assert(pos < size());
    return start_[pos];
}
const T &operator[](size_t pos) const
{
    assert(pos < size());
    return start_[pos];
}

7.迭代器

iterator begin()
{
    return start_;
}
iterator end()
{
    return finish_;
}
const_iterator begin() const
{
    return start_;
}
const_iterator end() const
{
    return finish_;
}

8.成员类型

typedef T *iterator;
typedef const T *const_iterator;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值