【 C++ 】一篇搞懂 vector

目录
1.什么是vector
简单来说,vector是c++标准库提供的动态数组容器,它能像普通数组一样存储同类型元素,还能自动扩容缩容,不用手动管理内存。vector也支持下标访问数组元素。数据类型属于模版类,定义时必须指定存储的元素类型,比如vector<int>,vector<string>等,这个元素类型可以是内置类型,也可以是自定义类型。
2.系统如何分配内存
vector的成员函数有size()和capacity(),size()用来计算数组中的元素个数,capacity()用来计算vector已分配的内存能容纳的最大元素个数。当size==capacity时就会触发扩容机制,常常是通过增加元素导致的。
vector分配内存的流程如下:
当你进行对象实例化 vector<int>v 时,系统不强制分配内存,size=0,capacity=0,指针指向为空。当你首次添加元素时,系统会分配一块内存,此时size=1,capacity=初始容量。当进行扩容操作导致size=capacity时,系统会重新分配一块更大的内存,同时将旧内存中的元素移动到新内存并释放旧空间。
需要特别注意的是,vector的内存是连续的,这也是它支持随机访问的原因,但扩容时会分配一块新的内存,此时旧内存的地址就失效了。会产生迭代器失效的问题。vector析构时会自动释放分配的堆内存,无需手动释放。
3.模板实例化
vector是一个模版类,搞懂模版是如何实例化的也可以帮助更好的理解代码。
C++的模版是“泛型”的,定义时不指定具体类型
// 这是 vector 的简化模板定义(仅示意)
template <typename T>
class Vector {
private:
T* data; // T 是类型参数,还不确定是 int/string/...
public:
void push_back(const T& value) { /* ... */ }
};
这段代码本身无法编译成机器码(因为 T是未知的),只有当你写出vector<int>,vector<string>时,编译器才会把 T 替换成具体类型,生成对应的类代码 —— 这个 “替换 + 生成代码” 的过程,就是模板实例化。
按需实例化
模板类的成员函数,只有被调用时才会被实例化,未调用的成员函数不会生成代码
template <typename T>
class MyClass {
public:
void func1() { std::cout << "func1" << std::endl; }
void func2() { std::cout << "func2" << std::endl; }
};
int main() {
MyClass<int> obj;
obj.func1(); // 只有 func1 会被实例化,func2 不会生成代码
return 0;
}
模版实例化有3个特点:编译阶段进行处理,会检查类型是否匹配,按需生成。
4.代码具体细节
在实现vector类时需要注意旧内存释放的问题,这里我们定义了三个指针,分别是_start,_finihs和_end_of_storage,分别指向数组的起始位置,最后一个元素的位置,和内存分配的最后一个位置。但是在扩容时旧内存的地址就失效了,此时如果你不更新三个指针就会出现野指针的现象,计算出来的size和capacity也都是不准确的值。这里我们可以进行先保存后更新的操作。
我们在释放旧空间前,需要将旧空间的值拷贝或转移到新空间,如果我们用memcpy拷贝的话是浅拷贝。浅拷贝有一个问题,就是在vector的类型是string类型时,会出现string里指针指向同一块内存空间的现象,在析构时重复释放同一块内存。所以我们采用转移的操作避免这一现象。

5.vector的模拟实现
#pragma once
#include<assert.h>
#include<list>
namespace wh {
template <class T>
class vector {
public://不写public就无法访问类内的成员函数
typedef T* iterator;
typedef const T* const_iterator;
void reserve(size_t n)
{
if (n > capacity())
{
iterator tmp = new T[n]; //new的时候会调用T类型的默认构造函数
size_t old_size = size();
//memcpy(tmp, _start, sizeof(T) * size());//乘以字节数size()而不是n
for (size_t i = 0; i < size() ; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
_start = tmp;
_finish = _start + old_size;
_end_of_storage = _start + n;
}
}
vector() = default;//要求编译器显示定义默认构造函数
void clear()
{
_finish = _start;
}
//v(v1)
vector(const vector<T>& v)
{
clear();
reserve(v.size());
for (auto i = v.begin(); i != v.end(); ++i)
{
push_back(*i);
}
}
void swap(vector<T>& v)
{
swap(_start, v._start);
swap(_finish, v._finish);
swap(_end_of_storage, v._end_of_storage);
}
//v1=v2
vector<T>& operator=(const vector<T> v)
{
swap(v);
return *this;
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(size_t n, const T& val = T())
{
reserve(n);
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}
void push_back(const T& x)
{
if (_finish == _end_of_storage)
reserve(capacity() == 0 ? 4 : 2 * capacity());
*_finish = x;
++_finish;
}
void pop_back()
{
assert(!empty());
--_finish;
}
void erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
while (pos < _finish-1)
{
*pos = *(pos + 1);
pos++;
}
--_finish;
}
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _end_of_storage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + len;
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos + 1;
}
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _end_of_storage - _start;
}
iterator begin()
{
return _start;
}
const_iterator begin() const
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator end() const
{
return _finish;
}
bool empty()
{
return _finish == _start;
}
void resize(size_t n, T val = T())
{
if (n < size())
{
_finish =_start + n;
}
reserve(n);
while (_finish != _start + n)
{
*_finish = val;
++_finish;
}
}
T& operator[](size_t i) {
assert(i < size());
return _start[i];
}
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;
};
template <class Container>
void Print(const Container& v)//Print要在类外声明定义
{
for (auto i : v)
{
cout << i << " ";
}
cout << endl;
}
}
更多推荐




所有评论(0)