C C++最新C++初阶:vector_vector 不是模板,腾讯C C++面试

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

[first,last) 左闭右开的方式。

//[]
for (size_t i = 0; i < v.size(); i++) {
    v1[i] += 1;
}

//iterator
vector<int>::iterator it = v.begin();
while (it != v.end()) {
    cout << \*it << " ";
    it++;
}

for (auto e : v) {
    cout << e << " ";
}

1.4 修改操作
接口声明解释
void push_back (const value_type& val)尾插
void pop_back()尾删
iterator insert (iterator pos, const value_type& val)迭代器位置插入
void insert (iterator pos, size_type n, const value_type& val);迭代器位置插入
void insert (iterator pos, InputIter first, InputIter last)迭代器位置插入一段区间
iterator erase (iterator pos)迭代器位置删除
iterator erase (iterator first, iterator last)删除一段迭代器区间
void assign (size_type n, const value_type& val)覆盖数据
v.insert(ret, 30);
v.insert(ret, 2, 30);
v.insert(ret, v2.begin(), v2.end());
v1.erase(pos);
v1.erase(v1.begin(), v1.end());

#include <algorithm>
// 查找接口
template <class InputIter, class T>
   InputIter find (InputIter first, InputIter last, const T& val);

2. vector的模拟实现

在这里插入图片描述

2.1 类的定义
template <class T, class Alloc = alloc>
class vector {
public:
    typedef T\* iterator;
    // ...
private:
    iterator start;
    iterator finish;gggg
    iterator end_of_storage;
}

这个结构和顺序表结构稍有不同,但本质是一样的。只是将容量和元素个数的变量用指向对应位置的迭代器代替。

class Seqlist {
    T\* _a;            /\* start \*/
    size_t _size;     /\* finish - start \*/
    size_t _capacity; /\* end\_of\_storage - start \*/
}

2.2 默认成员函数
//default constructor
vector()
    : \_start(nullptr)
    , \_finish(nullptr)
    , \_end\_of\_storage(nullptr)
{}
//fill constructor
vector(size_t n, const T& val = T()) // 引用临时对象可延长其声明周期
    : \_start(nullptr)
    , \_finish(nullptr)
    , \_end\_of\_storage(nullptr)
{
    resize(n, val);  
}
//copy constructor
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.capacity(); i++)
    {
        _start[i] = v._start[i];
    }
    _finish = _start + v.size();
    _end_of_storage = _start + v.capacity();
}

//range constructor
template <class InputIterator>
vector(InputIterator first, InputIterator last) 
    : \_start(nullptr)
	, \_finish(nullptr)
	, \_end\_of\_storage(nullptr)
{
	while (first != last) 
	{
		push\_back(\*first++);
    }
}
//destructor
~vector() 
{
    delete[] _start;
    _start = _finish = _end_of_storage = nullptr;
}

// 现代写法
//copy constructor
vector(const vector<T>& v) 
    : \_start(nullptr)
	, \_finish(nullptr)
	, \_end\_of\_storage(nullptr)
{
    vector<T> tmp(v.begin(), v.end());
    swap(tmp);
}
//operator=
vector<T>& operator=(vector<T> v)  /\* pass by value \*/
{
    swap(v);
    return \*this;
}

从范围构造可以看出类模板中的函数也可以是函数模板。

迭代器的分类

函数模板的模板参数要传迭代器区间时,命名是有规定的,范围构造中的InputIterator就是一种指定的迭代器类型。因容器的结构各有不同,迭代器分为五种类型:

迭代器类型名称解释适用容器
input/output_iterator输入/输出迭代器只读迭代器只能读取,只写迭代器可以写入该位置的值无实际容器
forward_iterator向前迭代器只能向前移动(++),允许在迭代器位置进行读写forward_list
bidirectional_iterator双向迭代器可以双向移动(++,––),允许在迭代器位置进行读写list, map, set
random_access_iterator随机迭代器支持指针运算,可移动(++,––)任意跳转(+,–)读写(*)deque,vector,string

可以看出,下方的迭代器类型是上方的父类,也就是说下方迭代器满足上方的所有要求

划分出不同的迭代器类型,是为了限制传入的迭代器,因为其必须满足要求才能完成接下来的函数。

函数如果指明迭代器类型为InputIterator,意思是满足输入迭代器的要求的迭代器都可以作此参数。故此处我们可以传入任意的迭代器。

一般底层是数组连续空间的容器,例如 vector, string 等都是随机迭代器。

像双向链表这样的非连续空间的容器是双向迭代器。

2.3 容量接口
memcpy 浅拷贝问题
vector<string> v;
v.push\_back("11111111111111");
v.push\_back("11111111111111");
v.push\_back("11111111111111");
v.push\_back("11111111111111");
v.push\_back("11111111111111"); // 增容浅拷贝

出现问题是因为正好数组需要增容。模拟实现的reserve函数使用memcpy将原空间的内容按字节拷贝至新空间。

  1. 若 vector 存储的是内置类型,则浅拷贝没问题。
  2. 若 vector 存储的是自定义类型,浅拷贝使得新旧变量指向同一块空间。深拷贝调用拷贝构造或者赋值重载。

void reserve(size_t n) 
{
    if (n > capacity()) 
    {
        T\* tmp = new T[n];
        size_t oldSize = size();
        
        if (_start) 
        {
            //memcpy(tmp, \_start, size() \* sizeof(T)); // err
            for (int i = 0; i < size(); i++) 
            {
                tmp[i] = _start[i];//\_start指向的空间存任意类型都能完成深拷贝
            }
            
            delete[] _sta rt;
        }
        
        _start = tmp;
        _finish = _start + oldSize;
        _end_of_storage = _start + n;
    }
}

void resize(size_t n, T val = T())
{
    if (n > size())
    {
        reserve(n);
        while (_finish != _start + n)
        {
            \*_finish = val;
            ++_finish;
        }
    }
    else
    {
        _finish = _start + n;
    }
}

2.4 修改接口
iterator insert(iterator pos, const T& val)
{
    assert(_start <= pos && pos <= _finish); // 检查pos位置是否合法
    // 增容
    if (_finish == _end_of_storage) 
    {
        size_t sz = pos - _start;
        reserve(capacity() == 0 ? 4 : capacity() \* 2); //增容会导致迭代器失效,迭代器位置陈旧
        pos = _start + sz; //增容后更新pos
    }
    
    // 后移 [pos,\_finish)
    for (iterator end = _finish; end > pos; --end)
    {
        \*end = \*(end - 1);


![img](https://img-blog.csdnimg.cn/img_convert/f78ffb01b8bd15585ee5564702fb3e99.png)
![img](https://img-blog.csdnimg.cn/img_convert/469c92a7f8ea96a2f7892552c07ddaa0.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

nd - 1);


[外链图片转存中...(img-EwGp0Vt1-1715713639431)]
[外链图片转存中...(img-VypUcRPY-1715713639431)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值