C++学习笔记(16)——vector的使用与模拟实现


比喻与理解


一、定义

vector是一个可以动态增长的数组,即变长数组。它依靠类和对象的特性实现。

vector比string设计的更合理,减少了很多冗余的库函数。

二 、在使用层面

vector的使用与string相似,初始化与数组类似;
无流插入流提取——vector使用范围for实现打印;

vector的接口与stl保持一致通用。

三、在实现层面

  1. vector是一个可以动态增长的数组,即变长数组。它依靠类和对象的特性实现;
  2. 由于vector的设计在string之后吸收了相关的经验,它的设计比string更加合理;
  3. vector实现时无需手动提供下标与扩容;

不同编译器内部各个功能的实现使用了很多复杂的指针关系,当我们学习理解时应当将其简化成原生指针。

四、vector的成员变量

我们最好在成员变量声明处给出缺省值。

  private:
        //各个成员函数的使用成员变量前全部统一初始化,防止不同编译器的其他初始化
        iterator _start=nullptr; // 指向数据块的开始
        iterator _finish = nullptr; // 指向有效数据的尾
        iterator _endofstorage = nullptr; // 指向存储容量的尾

五、vector的迭代器

vector的结构允许我们使用原生指针去管理它,使用原生指针使其高效管理自身的内容。

// Vector的迭代器是一个原生指针
        typedef T* iterator;
        iterator begin()
        {  
            return _start;
        }

        iterator end()
        {
            return _finish;
        }
        typedef const T* const_iterator;    //迭代器指向的内容不能++

        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }
        const const_iterator cbegin() const
        {
            return _start;
        }
        const const_iterator cend() const
        {
            return _finish;
        }     

六、vector的容器函数

我们使用的定位容器位置的函数,返回的是容器元素的内存位置和相对位置差值。
设置const版本,可以让普通对象和const对象都使用同一个函数定位;

     capacity
        //size_t size()
        //{
        //    return _finish - _start;
        //}

        //size_t capacity()
        //{
        //    return _endofstorage - _start;
        //}

        size_t size() const
        {
            return _finish - _start;
        }

        size_t capacity() const
        {
            return _endofstorage - _start;
        }

       

七、vector的其他函数

1. reserve更新容器空间大小:vector_name.reserve(size_type);

适应性地扩大空间所有权,未赋予空间使用权;

void reserve(size_t n)
        {
            if(n>capacity())
            {
                T* tmp = new T[n];
                size_t sz = size();
                if (_start)
                {
                    //memcpy(tmp, _start, sizeof(T) * size());    //浅拷贝
                    
                    for (size_t i = 0; i < sz; i++)
                    {
                        tmp[i] = _start[i];
                    }
                    delete[] _start;
                }
                _start = tmp;
                _finish = sz + _start;
                _endofstorage = _start + n;
            }
        }

我们经判断后认为需要扩容时,会通过以新的空间大小n为准new一个新的对象,再将旧空间的内容深拷贝到新的空间内,其内存地址和容器所有权大小更新,空间使用权大小会保持不变;

2. resize大小:vector_name.resize(size_type n);

刚性地扩大或缩小空间使用权、使用权;

        // T int    
        // int类型没有构造函数的说法,但C++对int模板进行了升级,使其可以在与T()交接的情况下被认为有构造函数
        // T string 
        // t vector<int>
        //T()是匿名对象,用来接收各种数据类型
        void resize(size_t n, const T& value = T()) 
        {
            if (n < size())
            {
                 _finish = _start + n ;
            }
            else  
            { 
                reserve(n);
                while (_finish < _start + n)
                {
                    *_finish = value;
                    ++_finish;
                }
            }
        }
        

扩大或缩小对象的空间所有权大小果需要扩大空间则:

  1. 如果新的空间使用权size大小大于原容器空间所有权capacity大小,则需要同步扩大容器空间所有权capacity和空间使用权size,二者扩容到新地size为止(capacity可能会大于size),然后使用给定的value去填充size未利用空间,对象成员变量同步更新;
  2. 如果新的空间使用权size大小大于原对象空间size而小于capacity,则未利用的空间填充value
    ,需要先扩大容器,则会扩容直到可以存储我们的新对象大小,然后使用给定的value去填充未被使用的空间,其容器大小和空间使用权会更新;
  3. 如果需要缩小

resize()、(resize内含reserve)代码演示如下:

    void test3()
    {
        cout << "测试resize()" << endl;

        vector<int*> v1;
        v1.resize(10);

        vector<string> v2;
        v2.resize(10,"xxx");
        
        cout << "v1" << endl;
        for (auto e : v1)
        {
            cout << e << " ";
        }

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

在这里插入图片描述

3. vector的尾删函数: vector_name.pop_back();

 void pop_back()
        {
            erase(_finish-1);
        }

代码演示如下:

void test1()
{
    cout << "试验push_back" << endl;

    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(5);

    for (size_t i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;

    cout << "试验迭代器" << endl;
    vector<int>::iterator it = v.begin();
    while (it != v.end())
    {
        cout << *it << " ";
        it++;
    }
    cout << endl;

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

    cout << "试验pop_back" << endl;

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

}

在这里插入图片描述

4. vector的删除函数: vector_name.erase(size_type);

        iterator erase(iterator pos)
        {
            assert(pos>=_start);
            assert(pos<_finish);

            iterator it = pos + 1;
            while (it < _finish)
            {
                *(it - 1) = *it;
                ++it;
            }
            --_finish;
            return pos;
        }

代码演示如下:

void test5()
{
    cout << "测试erase()" << endl;
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    v.push_back(6);
    v.push_back(7);
    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;

    cout << "头删" << endl;
    v.erase(v.begin());
    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;

    cout << "中间删5" << endl;
    v.erase(v.begin() + 3);
    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;

    cout << "尾删" << endl;
    v.erase(v.end() -1);
    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;
    cout << endl;
}

在这里插入图片描述

八、vector的默认构造

默认构造函数、拷贝构造函数、赋值运算符重载、取地址及const取地址运算符重载、析构函数。

为了避免过耦合,下面我会把各个功能分开实现;

1. 默认构造函数:vector vector_name();

创建一个空的vector对象,其中T是vector中元素的类型。

  //构造函数
        vector()
            //:_start(nullptr)
            //, _finish(nullptr)
            //, _endofstorage(nullptr)
        {}

2. 带有初始大小的构造函数:vector vector_name(size_type n);

创建一个包含n个默认初始化元素的vector对象。

3. 带有初始值和大小的构造函数:vector vector_name(size_type n, const T& value);

创建一个包含n个值为value的元素的vector对象。
想要实现该功能必须先实现push_back()、reserve();
而想要实现push_back()就必须实习insert();

        iterator insert(iterator pos, const T& x)
        {
            assert(pos >= _start);
            assert(pos <= _finish);

            if (_finish == _endofstorage)
            {
                size_t len = pos - _start;
                reserve(capacity() == 0 ? 4 : capacity() * 2);
                pos = _start+len;   //扩容后pos失效,在此更新
            }

            iterator end = _finish - 1;
            while (end >= pos)  //挪动数据为插入腾出地方
            {
                *(end + 1) = *end;
                --end;
            }
            *pos = x;
            ++_finish;

            return pos;
        }



       void push_back(const T& x)
        {
            insert(end(), x);
        }



		vector(int n, const T& value = T())
            //:_start(nullptr)
            //,_finish(nullptr)
            //,_endofstorage(nullptr)
        {
            reserve(n);
            for (size_t i = 0; i < n; i++)
            {
                push_back(value);
            }
        }

4. 带有迭代器范围的构造函数:vector vector_name(InputIterator first,InputIterator last);

创建一个包含[first, last)范围内元素的vector对象,其中InputIterator是迭代器类型.

        template<class InputIterator>
        vector(InputIterator first, InputIterator last)
        //vector(size_t n, const T& value = T())面对v(int,int)时会出现混淆的问题
        //所以上面n的类型点名写成int,单独写一个int重载版本
            //:_start(nullptr)
            //, _finish(nullptr)
            //, _endofstorage(nullptr)
        {
            while (first != last)
            {
                push_back(*first);
                ++first;
            }
        }

1-3函数代码演示如下:

void test7()
{
    cout << "测试各种初始化()" << endl;

    vector<string> v1(10, "xxxx");
    for (size_t i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;
    for (auto e:v1)
    {
        cout << e << " ";
    }
    cout << endl;

    vector<int> v2(10, 1);
    for (size_t i = 0; i < v1.size(); i++)
    {
        cout << v2[i] << " ";
    }
    cout << endl;
    for (auto e : v2)
    {
        cout << e << " ";
    }
    cout << endl;


    cout << endl;
    cout << endl;
}

在这里插入图片描述

5. 拷贝构造函数:vector vector_name_1(vector_name_2);

        //拷贝构造C        
        vector(const vector<T>& v)
            //:_start(nullptr)
            //, _finish(nullptr)
            //, _endofstorage(nullptr)
        {
            reserve(v.capacity());
            for (auto& e : v) 
            {
                push_back(e);
            }
        }

代码演示如下:

    void test6()
    {
        cout << "测试拷贝构造()" << endl;
        vector<int> v1;
        v1.push_back(1);
        v1.push_back(2);
        v1.push_back(3);
        for (auto e : v1)
        {
            cout << e << " ";
        }
        cout << endl;


        vector<int> v2(v1);
        for (auto e : v2)
        {
            cout << e << " ";
        }
        cout << endl;

        vector<int> v3;
        v3 = v1;
        for (auto e : v1)
        {
            cout << e << " ";
        }
        cout << endl;
        cout << endl;
    }

在这里插入图片描述

6. 赋值运算符重载:vector_name_1=vector_name_2;

//想要实现赋值运算符重载,必须先实现swap()函数

        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endofstorage, v._endofstorage);
        }

		vector<T>& operator=(vector<T> tmp)
        {
            swap(tmp);
            return *this;
        };	

7. 析构函数: ~vector()

        //析构函数
        ~vector()
        {
            delete[] _start;
            _start = _finish = _endofstorage = nullptr;
        }

8. const取地址运算符重载: vector_name[size_type n]

        T& operator[](size_t pos)
        {
            assert(pos < size());
            return _start[pos];
        }
        
  //前面的const:返回值不能改动;后面的const:指定const对象调用该函数
        const T& operator[](size_t pos) const
        {
            assert(pos < size());
            return _start[pos];
        }

9. find()寻找元素

vector里面没有自己的find,在算法库里面有通用的find模板。
只有string的find是自己自带的,其专门针对字符与字符串的情况;

        vector<int> vv(10,0);
        cout<<find(vv.begin(),vv.end(),1);

代码演示如下:


   void test8()
   {
       cout << "find()" << endl;
       vector<int> vv(10,0);
       cout<<find(vv.begin(),vv.end(),1);
   }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值