C++奇迹之旅:手写vector模拟实现与你探索vector 容器的核心机制与使用技巧

请添加图片描述


📝基本框架

我们先定义自己的命名空间俩封装自定义的vector类,这样可以避免与标准库中的 vector 发生命名冲突。随即,我们定义模版类vector,三个成员变量都是迭代器,而vector迭代器又是原生指针,所以我们将指针取别名为iterator

框架代码:

namespace self
{
	template<class T>
	class vector
	{
	public:
		// 定义类型别名 iterator 和 const_iterator,用于表示指向元素的指针类型
		typedef T* iterator;
		typedef const T* const_iterator;

	private:
	private:
		iterator _start;            // 指向动态数组的起始位置
		iterator _finish;           // 指向当前数组中最后一个元素的下一个位置
		iterator _end_of_storage;   // 指向已分配内存的末尾(容量的终点)

	};
}

在这里插入图片描述
理解代码并添加注释如下:

namespace self
{
    template<class T>
    class vector
    {
    public:
        // 定义迭代器类型
        typedef T* iterator;
        typedef const T* const_iterator;

    private:
        // 数据成员
        iterator _start; // 指向容器中第一个元素的指针
        iterator _finish; // 指向容器中最后一个元素之后的位置
        iterator _end_of_storage; // 指向容器所分配的存储空间的尾部

        // 在这里添加其他成员函数和成员变量
    };
}

成员变量的的私有数据成员:

  • iterator _start;: 这个成员变量保存了一个指向容器中第一个元素的指针。
  • iterator _finish;: 这个成员变量保存了一个指向容器中最后一个元素之后的位置的指针。
  • iterator _end_of_storage;: 这个成员变量保存了一个指向容器所分配的存储空间的尾部的指针。

🌠 构造和销毁

🌉vector()

在这里插入图片描述

  1. 完全空值初始化:
vector()
	: _start(nullptr)
	, _finish(nullptr)
	, _end_of_storage(nullptr)
{}
  1. 缺省值初始化
	vector() {};

private:
	iterator _start = nullptr;            // 指向动态数组的起始位置
	iterator _finish = nullptr;           // 指向当前数组中最后一个元素的下一个位置
	iterator _end_of_storage = nullptr;   // 指向已分配内存的末尾(容量的终点)

3.或者我们也可以偷个懒,让编译器自己生成

//强制编译器生成默认构造函数
vector() = default;

🌉vector(const vector& v)

这个构造函数是 vector 类的拷贝构造函数,用于创建一个新的 vector 对象,它是现有 vector 对象的拷贝。

vector(const vector<T>& v)
{
    reserve(v.size());
    for (auto e : v)
    {
        push_back(e);
    }
}

这是一个拷贝构造函数,它接受一个 const 引用类型的 vector 对象 v 作为参数。这个函数的目的是创建一个新的 vector 对象,并将传入的 vector 对象 v 的内容拷贝到这个新的 vector 对象中。

这个拷贝构造函数的实现逻辑:

  1. 预留空间:首先调用 reserve() 函数为目标 vector 预留足够的空间来存储源 vector 的所有元素。这样可以避免在元素插入过程中多次分配内存,提高性能。

  2. 拷贝元素:通过范围基于 for 循环遍历源 vector 中的每个元素,并使用 push_back() 将这些元素逐个添加到目标 vector 中。
    push_backreserve()下文会有讲解。

🌉vector(size_t n, const T& value = T())

重载构造函数,用于创建一个 vector 对象,并将其初始化为 n 个指定值 value

vector(size_t n, const T& value = T())
{
    for (size_t i = 0; i < n; ++i)
    {
        push_back(value);
    }
}
  • 这是一个带有两个参数的构造函数:

    • n:表示 vector 中元素的数量。
    • value:表示每个元素的初始值,默认值为 T(),即 T 类型的默认构造值。
  • 这个构造函数用于创建一个 vector 对象,并将其初始化为 n 个相同的元素,每个元素的值为 value

  • const T& 表示一个对 T 类型的常量引用。使用常量引用可以避免在函数内部修改传入的值,并且通常比传值的方式更加高效,因为避免了不必要的复制操作。

  • value 是参数的名字,它代表了要初始化 vector 中每个元素的值。

  • T()T 类型的默认构造函数的调用。它创建了一个 T 类型的对象,并使用默认构造函数来初始化它。

  • T() 表示调用 T 类型的默认构造函数,生成一个 T 类型的临时对象。对于内置类型(如 int, double),这通常是将其初始化为零;对于用户定义的类型(类或结构体),则会调用该类型的默认构造函数

默认参数的作用:当构造函数被调用而未提供 value 参数时,value 会被初始化为 T(),即一个 T 类型的默认值。

  • 如果提供了 value 参数,那么构造函数会使用提供的值,而不是默认值。

假设 T 是一个简单的类或结构体:

class Example {
public:
    int data;
    Example() : data(0) {}  // 默认构造函数,将 data 初始化为 0
    Example(int val) : data(val) {}
};

vector 的构造函数中:

vector(size_t n, const T& value = T())
{
    for (size_t i = 0; i < n; ++i)
    {
        push_back(value);
    }
}
  • 当你调用 vector(5)value 会被初始化为 T(),即 Example(),因此所有元素将会使用 Example 的默认构造值(data 为 0)。
  • 当你调用 vector(5, Example(10))value 被初始化为 Example(10),所有元素的 data 将会是 10。

总结:
T()const T& value = T() 中的作用是提供一个默认值用于初始化 value 参数。这个默认值是通过调用 T 类型的默认构造函数得到的。这样,构造函数在没有提供具体值的情况下,也能正确地初始化 vector 对象中的元素。

🌉赋值拷贝构造:vector& operator=(vector v)

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

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

赋值运算符重载 (operator=)

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

这里分为三部:
1.1. 参数 vector<T> v

  • 这个赋值运算符重载接受一个 vector<T> 对象 v 作为参数。这里的 v 是按值传递的,这意味着传递的是 v 的一个副本。
  • 传递副本而不是引用,有助于实现 强异常安全保证。如果在赋值过程中出现异常,原来的 vector 不会被影响。

1.2. swap(v)

  • swap(v) 是核心操作,它交换当前对象 (*this) 与传入的 v 对象的数据成员。
  • 这个操作通过交换指针来交换两个 vector 对象的内部数据(如起始位置 _start、结束位置 _finish、存储容量边界 _end_of_storage),而无需进行逐个元素的复制。
  • 交换后,传入的副本 v 原来持有的资源会被销毁,而当前对象将接管这些资源。

1.3. return *this

  • 最后返回当前对象的引用 *this,允许链式赋值操作,如 v1 = v2 = v3;

总结:
这种实现方式通过参数按值传递的副本,再通过交换数据来实现赋值运算,避免了临时资源分配失败导致的资源泄漏,并且非常高效,因为只交换指针,不进行实际数据复制。

  1. swap 函数
void swap(const vector<T>& v)
{
    std::swap(_start, v._start);
    std::swap(_finish, v._finish);
    std::swap(_end_of_storage, v._end_of_storage);
}

const vector<T>& v这里是引用:

swap 函数接受一个 const vector<T>& v 作为参数。因为这个函数只是交换内部指针,v 被声明为 const 是为了表明不会修改 v 的逻辑内容(但实际上会修改 v 的内部指针)。 std::swap 是标准库中的模板函数,交换两个变量的值。这里通过交换 _start_finish_end_of_storage 三个指针,实现了两个 vector 对象之间的数据交换。
函数效果:交换完成后,原对象和传入的对象交换了内部数据指针,但没有改变实际存储的数据。这种方式避免了内存分配和数据复制操作的开销,提高了效率。

🌉模版函数实现区间初始化 vector(InputIterator first, InputIterator last)

这个构造函数是一个模板函数,目的是让 vector 类支持任意类型的迭代器区间初始化。通过这个构造函数,你可以使用两个迭代器来初始化一个 vector 对象,将迭代器区间 [first, last) 中的所有元素插入到 vector 中。让我们逐步分析这段代码:

//类模版中也可以使用函数模版
//函数模版 --- 目的支持任意容易得迭代器区间初始化
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

🌉函数模板的定义 InputIterator

template<class InputIterator>
vector(InputIterator first, InputIterator last)
  • 这是一个函数模板,用于在 vector 类中定义一个构造函数。InputIterator 是模板参数,表示输入迭代器的类型。由于这是一个模板函数,所以它可以接受任意类型的迭代器。
  • firstlast 是两个迭代器,定义了一个半开区间 [first, last)。这个区间的所有元素将被复制到新的 vector 中。

循环遍历迭代器区间

while (first != last)
{
    push_back(*first);
    ++first;
}

while (first != last):这个 while 循环用于遍历迭代器区间 [first, last)。只要 first 不等于 last,就会继续循环。

push_back(*first)

  • *first 是解引用操作,获取当前 first 所指向的元素值。
  • push_back(*first) 将这个值添加到 vector 的末尾。
  • push_back() 函数会处理必要的内存扩展,因此即使 vector 当前容量不足,它也能动态扩展存储空间,以容纳新元素。

函数的功能和用途

  • 功能:这个模板构造函数允许你用任意的迭代器区间来初始化一个 vector。这个区间可以是数组、std::liststd::setstd::deque 等容器的迭代器区间,甚至是原始指针。

  • 用途:这种灵活性使得 vector 可以从几乎任何标准容器或数组中初始化。例如,如果你有一个数组 int arr[] = {1, 2, 3, 4};,可以使用这个构造函数将 arr 的内容复制到 vector 中:

    vector<int> vec(arr, arr + 4);
    

🌉列表初始化区间vector(initializer_list il)

vector(initializer_list<T> il)
{
	reserve(il.size());
	for (auto e : il)
	{
		push_back(e);
	}

}

这段代码是 vector 类的一个构造函数,它接受一个 initializer_list<T> 类型的参数来初始化 vectorinitializer_list 是 C++11 引入的一个特性,允许以列表的形式直接初始化容器。下面详细分析这段代码的每一部分:

vector(initializer_list<T> il)
  • initializer_list<T> 是 C++11 中引入的标准库类型,表示一个初始化列表,它是一个常量迭代器区间,支持对 T 类型的元素进行初始化。
  • il 是构造函数的参数,代表一个初始化列表,其中包含了要插入到 vector 中的元素。
reserve(il.size());
  • reserve()vector 类的一个成员函数,用于预先分配一定的内存空间,以避免在添加元素时频繁重新分配内存。
  • il.size() 返回初始化列表中元素的数量。调用 reserve(il.size()) 可以确保 vector 在添加所有元素之前有足够的空间,从而提高性能。
for (auto e : il)
{
    push_back(e);
}
  • 范围基于 for 循环 (for (auto e : il)) 遍历初始化列表 il 中的每一个元素。

    • auto 关键字让编译器自动推断 e 的类型,这里 eT 类型。
    • il 是一个 initializer_list<T>,它提供了迭代器接口,因此可以用这种方式进行遍历。
  • push_back(e) 将当前元素 e 插入到 vector 的末尾。

    • push_back() 方法会将元素 e 添加到 vector 中。如果 vector 的当前容量不足以容纳新的元素,它会自动扩展容量。

优点和使用场景

  • 易用性:支持直接使用花括号初始化列表,例如:
    self::vector<int> v = {1, 2, 3, 4, 5};
    
    这种方式非常直观,易于理解和使用。

示例

假设我们有一个 vector<int>,我们可以使用这个构造函数初始化 vector

self::vector<int> v = {1, 2, 3, 4, 5};
  • 这个语句会创建一个 vector<int> 对象 v,并将初始化列表 {1, 2, 3, 4, 5} 中的元素依次插入到 vector 中。

🌉~vector()

析构函数,我们只需要释放空间并置指针指向空:

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

🌠begin与end

迭代器开始与结束:

iterator begin()
{
	return _start;
}

iterator end()
{
	return _finish;
}

iterator begin() const
{
	return _start;
}

iterator end() const
{
	return _finish;
}

const_iterator cbegin() const
{
	return _start;
}

const_iterator cend() const
{
	return _finish;
}

获取容量大小与有效元素个数,只需要进行对应指针相减

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

size_t capacity() const
{
	return _end_of_storage - _start;
}
🌉reserve
void reserve(size_t n)
{
	if (n > capacity())
	{
		size_t old_size = size();//记录原size()的大小
		T* tmp = new T[n];

		if (_start)
		{
			memcpy(tmp, _start, sizeof(T) * size());
			delete[] _start;
		}

		_start = tmp;
		_finish = _start + old_size;//避免使用原来finish指针与更新后的start指针相减得到错误的size()
		_end_of_storage = _start + n;
	}

}

在这里插入图片描述
这个 reserve 函数用于在 vector 类中预留一定的内存,以便容纳 n 个元素。这个方法的主要目的是扩展 vector 的容量,确保它能够容纳更多的元素,同时管理内部内存的重新分配。下面详细分析这段代码:

函数实现

void reserve(size_t n)
{
    if (n > capacity())
    {
        size_t old_size = size(); // 记录原 size() 的大小
        T* tmp = new T[n]; // 分配新的内存空间

        if (_start)
        {
            memcpy(tmp, _start, sizeof(T) * size()); // 复制原有元素
            delete[] _start; // 释放原内存
        }

        _start = tmp; // 更新 start 指针
        _finish = _start + old_size; // 更新 finish 指针
        _end_of_storage = _start + n; // 更新 end_of_storage 指针
    }
}

记录原大小

size_t old_size = size();
  • size() 返回 vector 中当前元素的数量。
  • old_size 用于记录当前 vector 中的元素数量,以便在内存扩展后,能够正确地设置 _finish 指针。
    因为不记录,等delete了_start,到这两部
    _start = tmp; // 更新 start 指针,_finish = _start + size(); 再用旧的减去一个释放的_start,就会有问题。

这里我们执行深拷贝,通过memcpy将旧数组的元素复制到新数组。需要注意的是,memcpy是基于字节的浅拷贝,如果vector实例化为string类,浅拷贝可能导致二次释放等问题。
在这里插入图片描述

虽然我的_start指向新空间并进行了深拷贝,但string类却进行了浅拷贝,仍然指向原始空间。为了解决这个问题,我们不能使用memcpy,而是需要通过赋值操作进行二次深拷贝。

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

		_start = tmp;
		_finish = tmp + old_size;
		_endofstorage = tmp + n;
	}
}
🌉resize
void resize(size_t n, const T& x = T())
{
	if (n < size()) // 如果新的大小小于当前大小
	{
		_finish = _start + n; // 将_finish指针移动到新大小的位置
	}
	else if (n > size()) // 如果新的大小大于当前大小
	{
		size_t oldSize = size();
		reserve(n); // 确保有足够的容量来存储新大小的元素

		for (size_t i = oldSize; i < n; ++i)
		{
			push_back(x); // 用默认值x填充新的元素
		}
	}
	// 如果 n 等于当前大小,不需要进行任何操作
}

如果新大小小于当前大小,则截断容器中多余的元素;如果新大小大于当前大小,则使用给定的填充值来填充新的元素。

🌉insert与erase

在这里插入图片描述

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

	if (_finish == _end_of_storage)
	{
		size_t len = pos - _start;
		size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
		reserve(newcapacity);

		pos = _start + len;
	}

	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;
	++_finish;

	return pos;
}

插入位置检查: 确保插入位置 posvector 当前元素的范围内,即在有效的 [start, finish] 区间内。
内存扩展

if (_finish == _end_of_storage)
{
    size_t len = pos - _start;
    size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
    reserve(newcapacity);

    pos = _start + len;
}
  • 如果 vector 当前容量已满(_finish == _end_of_storage),则需要扩展容量。
  • 计算插入位置在原始 vector 中的索引 len,并使用 reserve(newcapacity) 扩展容量。
  • 扩展容量后,更新 pos 的位置,使其指向新的内存区域中插入的目标位置。这里 pos = _start + len 是为了确保扩展后的 pos 位置正确。
    这里的len记录原来位置是防止迭代器失效问题:因为我们使用了reserve,开了新空间,如果未保存,使用新的地址,那将会有风险。

返回值

return pos;
  • 返回新插入元素的位置 pos,使得插入操作可以链式使用,更新迭代器。

在 C++ 中,std::vector 是一个动态数组,它会根据需要扩展其内部存储的容量。由于这种扩展和其他操作,vector 中的迭代器可能会失效。以下是 vector 中迭代器失效的主要条件:

  1. 内存重新分配

vector 会在需要时扩展其内存容量。当 vector 的容量不足以容纳新元素时,它会重新分配内存。这通常发生在以下操作时:

  • 插入元素:当 vector 的容量满时,使用 push_backinsert 等方法插入新元素可能会触发内存重新分配。
  • 扩展容量:使用 reserve 增加 vector 的容量,如果 reserve 请求的容量大于当前容量,vector 可能会重新分配内存。

影响

  • 内存重新分配会导致所有原有的指针和迭代器失效,因为 vector 内部的元素被移动到新的内存位置。
  • 在内存重新分配后,原来的迭代器和指针将不再有效,因为它们指向的是旧的内存区域。
  1. 删除元素

删除元素通常不会导致内存重新分配,但会影响迭代器的有效性:

  • erase:调用 erase 方法删除元素会使指向被删除元素的迭代器失效。
  • 范围删除erase 删除一段范围内的元素时,范围内的所有迭代器会失效,此外,所有指向被删除元素之后的迭代器也会失效,因为元素的后续位置发生了改变。

影响

  • erase 操作可能导致指向被删除元素的迭代器失效。
  • 被删除元素之后的所有迭代器也会失效,因为删除操作可能会导致元素的重新排列。

在对 vector 进行赋值或移动操作时,虽然这些操作不会直接影响单个迭代器,但会对迭代器的使用产生影响:

  • 赋值操作:将一个 vector 赋值给另一个 vector,会涉及到内存重新分配和元素复制,这可能会使原有的迭代器失效。
  • 移动操作:使用移动构造函数或移动赋值操作时,也可能导致内部数据的重新分配和元素的重新排列,从而使迭代器失效。

为了避免迭代器失效的影响,在进行可能导致失效的操作后,应当重新获取迭代器或使用容器提供的稳定操作。例如,可以使用 vector 提供的 begin()end() 重新获取迭代器。在设计使用迭代器的代码时,应考虑这些因素,以确保代码的正确性和可靠性。
在这里插入图片描述

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

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

	--_finish;
	return pos;
}

迭代器失效 :删除操作会使指向被删除元素的迭代器失效。删除一个元素,迭代器还指向原位置,但元素被移动了,也就是原位置的后一个元素来到原位置,因此注意 erase 后,pos 之后的迭代器要更新指向新位置。

🌉push_back与pop_back

push_back函数可以复用,也可以使用insert的方法构造:

void push_back(const T& x)
{
	//if (_finish == _end_of_storage)
	//{
	//	size_t newcapacity = capacity() == 0 ? 4 : sizeof(T) * 2;
	//	reserve(newcapacity);
	//}
	//*_finish = x;
	//_finish++;

	insert(end(), x);
}
void pop_back()
{
	assert(size() > 0);
	--_finish;

}

🌠访问元素

访问元素operator[]需要注意的就是,要判断是否pos访问的位置合法:

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的实现是否有问题:

🌉test.cpp
# define _CRT_SECURE_NO_WARNINGS 1
#include "vector.h"

int main()
{
	//self::test_vector01();
	//self::test_vector02();
	//self::test_vector03();
	//self::test_vector04();
	//self::test_vector05();
	//self::test_vector06();
	//self::test_vector07();
	self::test_vector08();

	return 0;
}
🌉vector.h
#pragma once
#include <iostream>
#include <list>
#include <assert.h>
using namespace std;

namespace self
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		iterator begin() const
		{
			return _start;
		}

		iterator end() const
		{
			return _finish;
		}

		const_iterator cbegin() const
		{
			return _start;
		}

		const_iterator cend() const
		{
			return _finish;
		}

		//强制编译器生成默认构造函数
		vector() = default;

		//s2(s1)
		vector(const vector<T>& v)
		{
			reserve(v.size());
			for (auto e : v)
			{
				push_back(e);
			}

		}

		vector(size_t n, const T& value = T())
		{
			for (size_t i = 0; i < n; ++i)
			{
				push_back(value);
			}
		}

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

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

		//类模版中也可以使用函数模版
		//函数模版 --- 目的支持任意容易得迭代器区间初始化
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		vector(initializer_list<T> il)
		{
			reserve(il.size());
			for (auto e : il)
			{
				push_back(e);
			}

		}

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

		size_t capacity()
		{
			return _end_of_storage - _start;
		}

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

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

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t old_size = size();//记录原size()的大小
				T* tmp = new T[n];

				//if (_start)
				//{
				//	memcpy(tmp, _start, sizeof(T) * size());
				//	delete[] _start;
				//}

				for (size_t i = 0; i < old_size; i++)
				{
					tmp[i] = _start[i];
				}
				delete[] _start;

				_start = tmp;
				_finish = _start + old_size;//避免使用原来finish指针与更新后的start指针相减得到错误的size()
				_end_of_storage = _start + n;
			}

		}

		void resize(size_t n, const T& x = T())
		{
			if (n < size()) // 如果新的大小小于当前大小
			{
				_finish = _start + n; // 将_finish指针移动到新大小的位置
			}
			else if (n > size()) // 如果新的大小大于当前大小
			{
				size_t oldSize = size();
				reserve(n); // 确保有足够的容量来存储新大小的元素

				for (size_t i = oldSize; i < n; ++i)
				{
					push_back(x); // 用默认值x填充新的元素
				}
			}
			// 如果 n 等于当前大小,不需要进行任何操作
		}

		void push_back(const T& x)
		{
			//if (_finish == _end_of_storage)
			//{
			//	size_t newcapacity = capacity() == 0 ? 4 : sizeof(T) * 2;
			//	reserve(newcapacity);
			//}
			//*_finish = x;
			//_finish++;

			insert(end(), x);
		}

		void pop_back()
		{
			assert(size() > 0);
			--_finish;

		}

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

			return  _start[pos];
		}

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

			return _start[pos];
		}

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

			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);

				pos = _start + len;
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;

			return pos;
		}

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

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

			--_finish;
			return pos;
		}
	private:
		iterator _start;
		iterator _finish;
		iterator _end_of_storage;

	};

	void test_vector01()
	{
		self::vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		v1.push_back(5);
		v1.push_back(4);

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

		self::vector<int>::iterator it = v1.begin();
		while (it != v1.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;

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

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

	void test_vector02()
	{
		self::vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);

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



		size_t x = 0;
		cin >> x;
		self::vector<int>::iterator it = find(v1.begin(), v1.end(), x);
		if (it != v1.begin())
		{
			it = v1.insert(it, 100);
			cout << *it << endl;
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

	}

	void test_vector03()
	{
		self::vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);

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

		size_t x = 0;
		cin >> x;
		self::vector<int>::iterator it = find(v1.begin(), v1.end(), x);
		if (it != v1.end())
		{
			it = v1.erase(it);

			if (it != v1.end())
				cout << *it << endl;
		}

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

		cout << typeid(it).name() << endl;
	}

	void test_vector04()
	{
		vector<int> v3;
		v3.push_back(1);
		v3.push_back(2);
		v3.push_back(3);
		v3.push_back(4);
		vector<int>::iterator it = v3.begin();
		while (it != v3.end())
		{
			if (*it % 2 == 0)
			{
				v3.erase(it);
			}
			else
			{
				++it;
			}
		}

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

	void test_vector05()
	{
		vector<int> v6;
		v6.push_back(1);
		v6.push_back(1);
		v6.push_back(1);
		for (auto e : v6)
		{
			cout << e << " ";
		}
		cout << endl;

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

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

	}

	void test_vector06()
	{
		int i = 0;
		int j(1);
		int k = int();
		int x = int(2);
		vector<string> v8(4, "xxxxx");
		for (auto e : v8)
		{
			cout << e << " ";
		}
		cout << endl;


		vector<int> v9(4u, 104);
		for (auto e : v9)
		{
			cout << e << " ";
		}
		cout << endl;


		vector<int> v10(v9.begin(), v9.end());
		for (auto e : v9)
		{
			cout << e << " ";
		}
		cout << endl;


	}

	void test_vector07()
	{
		vector<string> v8(4, "xxxxx");
		for (auto e : v8)
		{
			cout << e << " ";
		}
		cout << endl;


		list<int> It;
		It.push_back(100);
		It.push_back(100);
		It.push_back(100);
		It.push_back(100);

		list<int> v3(It.begin(), It.end());
		for (auto e : v3)
		{
			cout << e << " ";
		}
		cout << endl;


	}

	class A
	{
	public:
		A(int a = 0)
			:_a1(a)
			, _a2(0)
		{

		}

		A(int a1, int a2)
			:_a1(a1)
			, _a2(a2)
		{

		}
	private:
		int _a1;
		int _a2;
	};

	void test_vector08()
	{
		A aa1(1);
		A aa2(2, 2);
		const A& aa3 = { 1, 2 };

		A aa4 = 1;
		A aa5 = { 1,3 };

		vector<int> v1({ 1,2,3,4,5,6 });
		vector<int> v2 = { 1,2,3,4,5,8 };
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
		for (auto e : v2)
		{
			cout << e << " ";
		}
		cout << endl;

		auto il1 = { 1,2,3,4 };
		initializer_list<int> il2 = { 1,3,4 };
		cout << typeid(il1).name() << endl;
		cout << sizeof(il2) << endl;
		for (auto e : il2)
		{
			cout << e << " ";
		}
		cout << endl;

	}
}

🚩总结

请添加图片描述

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿森要自信

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值