C++ vector 核心功能解析与实现

目录

整体结构概述

赋值运算符重载

下标运算符重载

内存管理函数

元素访问函数

插入和删除操作

完整代码


在C++标准库中, vector 是一个非常常用的动态数组容器,它能够自动管理内存,并且提供了丰富的操作接口。本文将通过分析一段手写 vector 的核心代码,深入理解 vector 的底层实现原理。

整体结构概述

我们实现的 vector 类模板主要包含以下几个关键部分:

  1. 数据成员:用于管理动态数组的内存和元素范围。

  2. 赋值运算符重载:实现对象之间的赋值操作。

  3. 下标运算符重载:支持通过 [] 访问元素。

  4. 内存管理函数: reserve 和 resize 用于控制动态数组的容量和大小。

  5. 元素访问函数: front 和 back 用于获取容器的首元素和尾元素。

  6. 插入和删除操作: push_back 、 pop_back 、 insert 和 erase 用于元素的增删。

cpp 复制代码
cpp

template <typename T>

class vector {

private:

    iterator _start; // 指向动态数组起始位置

    iterator _finish; // 指向最后一个有效元素的下一个位置

    iterator _end_of_storage; // 指向动态数组容量的末尾位置

public:
    typesdef T* iterator;
    typesdef const T* const_iterator;

    // 以下是具体成员函数的实现

};

赋值运算符重载

cpp 复制代码
cpp

vector<T>& operator=(vector<T>& v) {

    swap(v);

    return *this;

}

现代化写法

该函数实现了 vector 对象之间的赋值操作。通过调用 swap 函数交换当前对象和传入对象的内部数据( _start 、 _finish 和 _end_of_storage ),从而高效地完成赋值。 swap 函数的具体实现通常会交换两个对象的资源,而不是逐个复制元素,这样可以提高效率。

下标运算符重载

cpp 复制代码
cpp

T& operator[](size_t pos) {

    assert(pos < size());

    return _start[pos];

}



const T& operator[](size_t pos) const {

    assert(pos < size());

    return _start[pos];

}

这两个函数实现了通过 [] 操作符访问 vector 中的元素。第一个函数是非 const 版本,用于修改元素;第二个函数是 const 版本,用于在 const vector 对象上读取元素。通过 assert 确保访问的下标在有效范围内,防止越界访问。

内存管理函数

reserve 函数

cpp 复制代码
void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t sz = size();
				t* tmp = new t[n];
				if (_start)
				{
					//memcpy(_tmp,_start,sizeof(T)*sz);
					for (size_t i = 0;i < sz;i++)
					{
						tmp[i] = _start[i];
					}
					delete[]_start;
				}
				_start = tmp;
				_finish = _start + sz;
				_end_of_storage = _start + n;

			}
		}

reserve 函数用于确保 vector 的容量至少为 n 。如果 n 大于当前容量,会分配一块新的更大的内存,将原有的元素逐个复制到新内存中,然后释放旧内存,并更新 _start 、 _finish 和 _end_of_storage 指针。

resize 函数

cpp 复制代码
cpp

void resize(size_t n, const T& val = T()) {

    if (n < size()) {

        _finish = _start + n;

    } else {

        reserve(n);

        while (_finish != _start + n) {

            *_finish = val;

            ++_finish;

        }

    }

}

resize 函数用于改变 vector 的大小。如果 n 小于当前大小,会截断 vector ;如果 n 大于当前大小,会先调用 reserve 确保有足够的容量,然后将新增位置初始化为 val 。

元素访问函数

front 函数

cpp 复制代码
cpp

T& front() {

    return *_start;

}



const T& front() const {

    return *_start;

}

front 函数用于获取 vector 的首元素。非 const 版本允许修改首元素, const 版本则用于在 const vector 对象上获取首元素。

back 函数

cpp 复制代码
cpp

T& back() {

    return *(_finish - 1);

}



const T& back() const {

    return *(_finish - 1);

}

back 函数用于获取 vector 的尾元素。同样分为非 const 和 const 版本,分别用于修改和读取尾元素。

插入和删除操作

push_back 函数

cpp 复制代码
cpp

void push_back(const T& x) {

    insert(end(), x);

}

push_back 函数在 vector 的末尾插入一个元素,它通过调用 insert 函数实现。

pop_back 函数

cpp 复制代码
cpp

void pop_back() {

    erase(end() - 1);

}

pop_back 函数删除 vector 的尾元素,通过调用 erase 函数实现。

erase 函数

cpp 复制代码
cpp

iterator erase(iterator pos) {

    iterator begin = pos + 1;

    while (begin != _finish) {

        *(begin - 1) = *begin;

        ++begin;

    }

    _finish--;

    return pos;

}

erase 函数删除指定位置的元素。通过将该位置之后的元素逐个向前移动,覆盖要删除的元素,然后更新 _finish 指针。

insert 函数

cpp 复制代码
cpp

iterator insert(iterator pos, const T& x) {

    assert(pos <= _finish);

    if (_finish == _end_of_storage) {

        size_t len = pos - _start;

        size_t new_cap = (capacity() == 0) ? 4 : capacity() * 2;

        reserve(new_cap);

        pos = _start + len;

    }

    iterator end = _finish - 1;

    while (end >= pos) {

        *(end + 1) = *end;

        end--;

    }

    *pos = x;

    _finish++;

    return pos;

}

insert 函数在指定位置插入一个元素。如果当前容量已满,会先调用 reserve 扩大容量,然后将插入位置之后的元素逐个向后移动,腾出空间插入新元素,并更新 _finish 指针。

通过以上代码的实现,我们可以对 vector 的核心功能有一个更深入的理解,掌握动态数组的内存管理和元素操作的底层原理。在实际开发中,合理使用 vector 可以提高代码的效率和可读性。

完整代码

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<assert.h>
namespace ldg
{
	template<class T>
	class vecctor
	{
	public:
		//原生指针
		typedef T* iterator;
		typedef const T* const_iterator;

		size_t size() {
			return _finish - _start;
		}

		size_t capacity()
		{
			return _end_of_storage - _start;
		}

		bool empty()const 
		{
			return _start == _finish;
		}

		iterator begin()
		{
			return _start;
		}

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

		const_iterator cend()const
		{
			return _finish;
		}
		//构造和销毁
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}

		vector(size_t n,const T& val=T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			reserve(n);
			while (n--) push_back(val);
			
		}

		vector(int  n, const T& val = T())
			:_start(new T[n])
			, _finish(_start+n)
			, _end_of_storage(_finish)
		{
			for (int i = 0;i < n;i++)_start[i] = val;
		}

		template <class Inititerator>
		vector(Inititerator first, Inititerator last)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}

		//vector(const vector<T>& v)
		//	:_start(nullptr)
		//	, _finish(nullptr)
		//	, _end_of_storage(nullptr)
		//{
		//	_start = new T[v.capacity()];
		//	//memccpy(_start,v._start,sizeof(T)*v.size());
		//	for (size_t i = 0;i < size();i++)
		//	{
		//		_start[i] = v._start[i];
		//	}
		//	_finish = _start + v.size();
		//	_ens_of_storage = _start + v.capacity();
		//}

		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			reserve(v.capacity());
			for (auto e : v)push_back(e);
			
		}

		~vector()
		{
			if (_start) {
				delete[]_start;
				_start = _finish = _end_of_storage = nullptr;
			}
		}

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

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

		T& operator[](size_t pos)
		{
			assert(pos < size());
			return _start[pos];
		}

		const T& operator[](size_t pos)const
		{
			assert(pos < size());
			return _start[pos];
		}

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

			}
		}
		void resize(size_t n, const T& val = T())
		{
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				reserve(n);

				while (_finish != _start + n)
				{
					*finish = val;
					++_finish;
				}
			}
		}

		T& front()
		{
			return *_start;
		}

		const T& front()const
		{
			return *_start;
		}

		T& back()
		{
			return *(finish-1);
		}

		const T& back()const
		{
			return *(finish - 1);
		}

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

		void pop_back()
		{
			ease(end() - 1);
		}
		//pos位置插入x
		
		//删除pos位置,返回pos+1
		iterator erase(iterator pos)
		{
			iterator begin = pos + 1;
			while (begin = _finish)
			{
				*(begin - 1) = *begin;
				++begin;
			}
			_finish--;
			return pos;
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos <= finish);
			if (_finish == _end_of_storage)
			{
				size_t len = pos-start;
				size_t newst = (capacity() == 0) ? 4 : capacity() * 2;
				reserve(newst);
				pos = _start + len;//防止迭代器失效
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				end--;
			}
			*pos = x;
			finish--;
			return pos;//防止迭代器失效
		}
		private:
			iterator _start;
			iterator _finish;
			iterator _end_of_storage;
	};
相关推荐
我不想当小卡拉米14 分钟前
【Linux】操作系统入门:冯诺依曼体系结构
linux·开发语言·网络·c++
炎芯随笔21 分钟前
【C++】【设计模式】生产者-消费者模型
开发语言·c++·设计模式
乌鸦94443 分钟前
《类和对象(下)》
开发语言·c++·类和对象+
逐光沧海1 小时前
数据结构基础--蓝桥杯备考
数据结构·c++·算法·蓝桥杯
前进的程序员1 小时前
嵌入式开发中 C++ 跨平台开发经验与解决方案
开发语言·c++
菜一头包2 小时前
c++ std库中的文件操作学习笔记
c++·笔记·学习
吃个早饭3 小时前
2025年第十六届蓝桥杯大赛软件赛C/C++大学B组题解
c语言·c++·蓝桥杯
阿沁QWQ4 小时前
单例模式的两种设计
开发语言·c++·单例模式
六bring个六4 小时前
qtcreater配置opencv
c++·qt·opencv·计算机视觉·图形渲染·opengl
qwertyuiop_i5 小时前
pe文件二进制解析(用c/c++解析一个二进制pe文件)
c语言·c++·pe文件