目录

1.什么是vector

2.系统如何分配内存

3.模板实例化

按需实例化

4.代码具体细节

5.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;
	}

​}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐