C++ ------>std :: vector__深浅拷贝
  L8iEHH07GzZb 2023年11月13日 31 0

各位好友, 本期 ------>Vector(容器)----->深浅拷贝 开战 !

----->代码如下 :>

------>头文件 “Vector.h” :>

//Vector(容器)模拟实现
namespace UC
{
  template<class T>
	class vector()
  {
  public:
    typedef T* iterator;
    typedef const T* const_iterator;
    
    iterator begin()
    {
    	return _start;
    }
    iterator end()
    {
    	return _finish;
    }
    const_iterator begin() const
    {
    	return _start;
    }
    const_iterator end() const
    {
    	return _finish;
    }
    
    //无参数构造
    vector()
    {}
   	vector(size_t n, const T& val= T())
    {
      resize(n, val);
    }
    
    //拷贝构造 ---->第一种写法
    vector(const T& v)
    {
      _start = new T[v.capacity()];
      
      //此处涉及到 浅拷贝, 会使得程序发生崩溃 !
      //memcpy(_start, v._start, sizeof(T) * v.size());
      
      //正确拷贝 赋值行为
      for(size_t i = 0; i < v.size(); i++)
      {
      	_start[i] = v._start[i];
      }
      
      _finish = _start + v.size();
      _endofstorge = _start + v.capacity();
    }
    
    //拷贝构造 ---->第二种写法
    vector(const T& v)
    {
    	reserve(v.capacity());
      for(auto e : v)
      {
      	  v.push_back(e);
      }
    }
    //多参数构造 ---->难点理解
    vector(size_t n, const T& val = T())
    {
    	resize(n, val);
    }
    vector(int n, const T& val = T())
    {
    	resize(n, val);
    }
    template<class InputIterator> //模板内可以再套用一个模板
    vector(InputIterator first, InputIterator last)
    {
    	while(first != last)
      {
      	push_back(*first);
        ++first;
      }
    }
    //扩容
    void reserve(size_t n)
    {
    	if(n > capacity())
      {
        size_t sz = size(); //注意 :>此处需要保存数值---->难点
        T* tamp = new T[n];
        
      	if(_start)
        {
          //此处涉及到 浅拷贝, 致使程序运行会发生错误
          ///memcpy(tamp, _start, sizeof(T) * sz);
          
          //正确拷贝赋值行为
          for(size_t i = 0; i < size(); i++)
          {
          	tamp[i] = _start[i];
          }
        	delete[] _start;
        }
        
        _start = tamp;
        _finish = _start + sz;
        _endofstoarge = _start + n;
      }
    }
    
    //追加数据
    void push_back(const T& x)
    {
    	insert(end(), x);
    }
    //插入数据
    iterator insert(iterator pos, const T& val)
    {
    	assert(pos >= _start && pos <= _finish);
      
      if(_finish == _endofstorge)
      {
      	size_t len = pos - _start;
        
        size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
        
        reserve(newCapacity);
        
        pos = len + _start;
      }
        
        iterator end = _finish - 1;
        while(end >= pos)
        {
        	*(end + 1) = *end;
          --end;
        }
        
        *pos = val;
        ++_finish;
      
      return pos;
    }
    void resize(size_t n, const T& val = T())
    {
    	if(n < size())
      {
        _finish = _start + n;
      }
      else
      {
      	while(_finish != _start + n)
        {
        	*_finish = val;
          ++_finish;
        }
      }
    }
    
    size_t size() const
    {
    	return _finish - _start;
    }
    size_t capacity() const
    {
    	return _endofstorge - _start;
    }
    
    T& operator[](iterator pos)
    {
      assert(pos < size());
    	return _start[pos];
    }
    const T& operator[](iterator pos)
    {
      assert(pos < size());
    	return _start[pos];
    }
    ~vector()
    {
      delete[] _start;
      
      _start = _finish = _endofstorge = nullptr;
    }
  private:
    iterator _start = nullptr;
    iterator _finish = nullptr;
    iterator _endofstorge = nullptr;
  }
}

----->测试环节 “Test.cpp” :>

//测试运行一组 ---->隐藏Bug

#include "Vector.h"

void test_01()
{
	UC :: vector<string> v1;
  
  v1.push_back("111111111111");
  v1.push_back("222222222222");
  v1.push_back("333333333333");
  
  for(auto e : v1)
  {
  	cout << e << " ";
  }
  cout << endl;
}

void test_02()
{
	UC :: vector<string> v1;
  
  v1.push_back("111111111111");
  v1.push_back("222222222222");
  v1.push_back("333333333333");
  
  v1.push_back("101010101010");
  v1.push_back("010101010101");
  
  for(auto= e : v1)
  {
    cout << e << " ";
  }
  cout << endl;
}

int man()
{
  test_0();
	return 0;
}

为了方便好友们, 有更好地观感体验, 现附上 彩色代码图样 :>

C++ ------>std :: vector__深浅拷贝_Vector__深浅拷贝


深拷贝  ------->致使拷贝赋值函数不足性 :>

C++ ------>std :: vector__深浅拷贝_模板下内再创建一个模板_02


深拷贝  ---------->致使扩容函数不足性 :>

C++ ------>std :: vector__深浅拷贝_Vector__深浅拷贝_03


------>测试 一 :>

C++ ------>std :: vector__深浅拷贝_Vector__深浅拷贝_04


------>测试 二 :>

C++ ------>std :: vector__深浅拷贝_Vector__深浅拷贝_05


------->针对上述情况, 做如下说明 :>

上述程序, 三个值的运行, 是可以拷贝成功 !但是 增加到 五个值的时候, 就会发生程序崩溃 !

------->原因 :> 隐藏的 深拷贝, 主要发生在扩容环节 !请看下列图示 :>

C++ ------>std :: vector__深浅拷贝_模板下内再创建一个模板_06

VS 2019 编译器下 存储 vector<string>对象

如果 该对象大小是在 16 字节之内 则会存储  在系统上提前开辟的一个 buff[16] 数组

------>如果 该对象大小 大于了 16字节

则编译器 会额外开辟一个新空间 来存储该对象 !而提前开辟好的空间就会浪费掉 !


另外补充一点 :>内置类型 深拷贝, 无须改动上述原先代码 !

---------------------------->因为 内置类型 深拷贝 又叫做 值拷贝 !

memcpy()函数对于内置类型没有任何问题, 但 对于自定义类型 就会发生崩溃现象 !

现对 memcpy()函数 深入 探究 !如下 :>

C++ ------>std :: vector__深浅拷贝_Vector__深浅拷贝_07

注意 :>T 作 自定义类型 时

-------->会依次调用数组内 每个对象的析构函数, 之后再调用 delete[]函数 -->销毁空间

-------->其中, tamp 没有发生 浅拷贝; 但是 tamp 内部对象 发生了 浅拷贝 !

即:>vector 是 深拷贝, 但是 vector 空间上 存在的对象 是 string 对象;

----------------------------->使用 memcpy()函数 导致 string 对象发生了 浅拷贝 !

经过 delete[]之后, 新空间内 拷贝没问题, 空间大小 也没问题

--------------->但是 string 对象 内部指针 --------->会变成 野指针 !


各位好友, 本期专栏 内容 已快要完结 !下面再扩展一个 vector ()函数 构造场景 !如下 :>

C++ ------>std :: vector__深浅拷贝_模板下内再创建一个模板_08

-------------------------->注意 :>新构造 vector 函数  ---->模板类型 是一致的 !(关键点)


测试 环节 一 :>

C++ ------>std :: vector__深浅拷贝_Vector__深浅拷贝_09


------>解决方案 :>

C++ ------>std :: vector__深浅拷贝_模板下内再创建一个模板_10


由此可见, 程序编译不通过 ! 具体原因 :>测试环节, 实参部分 前后类型不一致 !

----------->

至此, 本模块, vector (容器)模拟实现 ----->已完成 !

下一期, 终于 要向  List (链表)进行宣战了 !  “敬请期待 !😊😊


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

L8iEHH07GzZb