前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >从 C++ STD::VECTOR的RESIZE和RESERVE看VECTOR的源码实现

从 C++ STD::VECTOR的RESIZE和RESERVE看VECTOR的源码实现

作者头像
早起的鸟儿有虫吃
发布2022-01-20 19:29:32
发布2022-01-20 19:29:32
1.7K00
代码可运行
举报
文章被收录于专栏:算法之美算法之美
运行总次数:0
代码可运行

阅读收益:

Q 一个 T类

是如何被构造, 释放 拷贝

巨人肩膀

  • stl源码剖析

https://www.cnblogs.com/yocichen/p/10574819.html https://www.kancloud.cn/digest/stl-sources/177267

  • 其他

https://www.cnblogs.com/yocichen/p/10574819.html

https://blog.csdn.net/u013575812/article/details/51171135

  • 官方 https://www.cplusplus.com/reference/vector/vector/reserve/

第一步:搞清楚vector数据结构定义

思考60秒:sizeof(vector)大小多少?与size() 和capacity()有关系吗?

  1. 永远是3*8=24。跟扩容没关系
  2. capacity是指针 已经分配一片连续空间。与size()已经初始化的空间

1. vector 特点 是连续空间

啥意思 提前已经分配好内存了(M_start,_M_end_of_storage)。就能解释下吗2个概念。

  • 很多初学者分不清楚 vector 容器的容量(capacity)和大小(size)之间的区别,甚至有人认为它们表达的是一个意思

混淆地方。

  • capacity:已经分配的空间(用户不可见),---相当于 malloc 没有调用构造函数
  • size 代表 已经分配空间,已经初始化,---new 调用构造函数进行初始化。

可分配空间是vector之外的

思考60秒:vector(10,0) 执行过程

  • vector(10,0) 执行过程 a 执行_Vector_base构造函数 b 初始化size(10),调用对应构造函数 _M_finish =_M_end_of_storage=10; c:容器的容量(capacity)和大小(size)大小一样了 v1.size() == 15 v.capacity() = 15
    1. 申请空间 10*int空间
    2. 设置 _M_start = _M_finish =0 _M_end_of_storage=10
代码语言:javascript
代码运行次数:0
运行
复制
  
  class vector : protected _Vector_base<_Tp, _Alloc> 

   explicit vector(size_type __n)
    : _Base(__n, allocator_type())
    { 
        _M_finish = uninitialized_fill_n(_M_start, __n, _Tp()); 
     }
 
  
template <class _Tp, class _Alloc> 
class _Vector_base {
public:
  ~_Vector_base() { _M_deallocate(_M_start, _M_end_of_storage - _M_start); }

    _Vector_base(const _Alloc&)
    : _M_start(0), _M_finish(0), _M_end_of_storage(0) {}
  _Vector_base(size_t __n, const _Alloc&)
    : _M_start(0), _M_finish(0), _M_end_of_storage(0) 
  {
    _M_start = _M_allocate(__n); //申请n字节大小,返回开始地址
    _M_finish = _M_start;//构造时候 没有填充任何元素。vector<int>()
    _M_end_of_storage = _M_start + __n; //+n 说明是连续空间
  }
  
protected:
  _Tp* _M_start; //表示目前使用空间的 头
  _Tp* _M_finish; //表示目前使用空间的 尾
  _Tp* _M_end_of_storage; //表示目前使用空间 可用空间。
  

  typedef simple_alloc<_Tp, _Alloc> _M_data_allocator; //内存分配器
  //申请n字节空间 malloc
  _Tp* _M_allocate(size_t __n)
    { return _M_data_allocator::allocate(__n); }
  //释放:具体怎么实现的不清楚 
  void _M_deallocate(_Tp* __p, size_t __n) 
    { _M_data_allocator::deallocate(__p, __n); }
};

 _Tp* _M_allocate(size_t __n)
    { return _M_data_allocator::allocate(__n); }
    
  //Return size of allocated storage capacity
  //分配的空间大小。在构造时候已经预先分配
  size_type capacity() const
    { return size_type(_M_end_of_storage - begin()); }
    
  • std::vector::reserve Request a change in capacity

第二步 查看 insert函实现

case1-a:对应的源代码解析中的case1-a情况;

case1-b:对应源码剖析中的case1-b情况:

第三步:查看 push_back()

  • push_back 函数:construct
代码语言:javascript
代码运行次数:0
运行
复制
  void push_back(const _Tp& __x) {//在最尾端插入元素
    if (_M_finish != _M_end_of_storage) {//若有可用的内存空间
      construct(_M_finish, __x);//构造对象
      ++_M_finish;
    }
    else//若没有可用的内存空间,调用以下函数,把x插入到指定位置
      _M_insert_aux(end(), __x);
  }
  
inline void construct(_T1* __p, const _T2& __value) {
  _Construct(__p, __value);
}


  
template <class _T1, class _T2>
//构造函数执行:new()
//http://www.cplusplus.com/reference/new/operator%20new/
//new (p2) MyClass;
inline void _Construct(_T1* __p, const _T2& __value) {
  new ((void*) __p) _T1(__value);
}
//调用构造函数 new (p)MyClass():
template <class _T1>
inline void _Construct(_T1* __p) {
  new ((void*) __p) _T1();
}
//调用释放函数
template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
  __pointer->~_Tp();
}
  
  
  

  
  
  • 插入函数:vector<_Tp, _Alloc>::_M_insert_aux(iterator __position, const _Tp& __x) 停留60秒,思考一下 插入一个T元素执行过程?和直接new元素区别?
  1. 计算新容器大小:2 * __old_size (__old_size >0 )
  2. 分配 len 空间。
  3. memmove 拷贝之前元素
  4. 调用构造函数插入x元素

construct(__new_finish, __x); //调用构造函数 new(__new_finish)x()

  1. memmove 拷贝之后元素。

bitcoyp 无论里面是什么元素 6 释放old

  • 6.1 根据地址 调用析构函数

construct--> __p->~_Tp()

  • 6.3 回收该地址

_M_data_allocator::deallocate(__p, __n);

7 设置三个指针位置到全局变量

代码语言:javascript
代码运行次数:0
运行
复制
  
void construct(pointer __p, const _Tp &__val) { new (__p) _Tp(__val); }

inline wchar_t* 
uninitialized_copy(const wchar_t* __first, const wchar_t* __last,
                   wchar_t* __result)
{
  memmove(__result, __first, sizeof(wchar_t) * (__last - __first));
  return __result + (__last - __first);
}
  

  template <class _Tp, class _Alloc>
void 
vector<_Tp, _Alloc>::_M_insert_aux(iterator __position)
{
  if (_M_finish != _M_end_of_storage) {
    construct(_M_finish, *(_M_finish - 1));
    ++_M_finish;
    copy_backward(__position, _M_finish - 2, _M_finish - 1);
    *__position = _Tp();
  }
  else {
    const size_type __old_size = size();
    const size_type __len = __old_size != 0 ? 2 * __old_size : 1; //step1 len=2n
    //new 
    iterator __new_start = _M_allocate(__len); //step2 alloc  len
    iterator __new_finish = __new_start;
    __STL_TRY {
      __new_finish = uninitialized_copy(_M_start, __position, __new_start);
      
      construct(__new_finish);
      ++__new_finish;
      __new_finish = uninitialized_copy(__position, _M_finish, __new_finish);
    }
    //02 free 
    __STL_UNWIND((destroy(__new_start,__new_finish), 
                  _M_deallocate(__new_start,__len)));
    destroy(begin(), end()); // ~T()
    _M_deallocate(_M_start, _M_end_of_storage - _M_start); // 回收地址
    
    //reset
    _M_start = __new_start;
    _M_finish = __new_finish;
    _M_end_of_storage = __new_start + __len;
  }
}

大家都知道的

别人知道,我不知道的

收益:停留60秒回忆 new 和malloc ,free delete?

收益:停留60秒回忆 strcpy和memcpy区别?

复制的内容不同。

  • strcpy只能复制字符串,
  • 而memcpy/memmove可以复制任意内容,例如字符数组、整型、结构体、类等。

memmove

  • void * memmove ( void * destination, const void * source, size_t num );
代码语言:javascript
代码运行次数:0
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
 
void* memmove(void* dest, void* source, size_t count) {
 
 char* ret = (char*)dest;
 const char* src =(char*) source;
 if (dest <= source || dest >= (source + count)) {
  //正向拷贝
  //copy from lower addresses to higher addresses
  while (count--)
   *(ret++) = *(src++);
 } else {
  //反向拷贝
  //copy from higher addresses to lower addresses
  while (count--)
   *(ret + count) = *(src + count);
 }
 return ret;
}

总结 一个 类 是如何被构造,释放 和 拷贝的。

代码语言:javascript
代码运行次数:0
运行
复制

  uninitialized_copy(const wchar_t* __first, const wchar_t* __last,
                   wchar_t* __result)
{
  memmove(__result, __first, sizeof(wchar_t) * (__last - __first));
  return __result + (__last - __first); //直接跳转 
}
  
   construct(__new_finish, __x); //调用构造函数 new(__new_finish)x()
  
  
  void construct(pointer __p, const _Tp &__val) { new (__p) _Tp(__val); }
  
  
  void destroy(pointer __p) { __p->~_Tp(); }
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Offer多多 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 阅读收益:
  • 巨人肩膀
  • 第一步:搞清楚vector数据结构定义
    • 思考60秒:sizeof(vector)大小多少?与size() 和capacity()有关系吗?
    • 1. vector 特点 是连续空间
    • 思考60秒:vector(10,0) 执行过程
  • 第二步 查看 insert函实现
  • 第三步:查看 push_back()
  • 总结 一个 类 是如何被构造,释放 和 拷贝的。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档