STL-vector(使用和部分模拟实现)

1.vector(类模板)

  1. vector是表示可变大小数组的序列容器。

  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。

  3. vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。

  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。

  5. vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。

  6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。

2.vector的使用

2.1构造函数

cpp 复制代码
void test()
{
	//无参构造
	vector<int> v1;
	//构造并初始化n个val
	vector<int> v2(10, 6);//10个6
	vector<int> v3(10);//10个0
	//拷贝构造
	vector<int> v4(v2);
	//initializer_list初始化构造
	vector<int> v5 = { 5,4,3,6,7 };
	//使用迭代器进行初始化构造
	vector<int> v6(v5.begin() + 2, v5.end());
	//构造二维数组
	vector<vector<int>> vv(5, vector<int>(6, 6));
	for (int i = 0; i < vv.size(); i++)
	{
		for (int j = 0; j < vv[0].size(); j++)
		{
			cout << vv[i][j] << ' ';
		}
		cout << endl;
	}
}

2.2 operator=

用于赋值(不是拷贝构造)

cpp 复制代码
void test4()
{
	//operator=
	vector<char> v1 = { 'a', 'b', 'c' };
	vector<char> v2;
	for (auto e : v1)
	{
		cout << e << ' ';
	}
	cout << endl;
	for (auto e : v2)
	{
		cout << e << ' ';
	}
	cout << endl;
	v2 = v1;
	for (auto e : v1)
	{
		cout << e << ' ';
	}
	cout << endl;
	for (auto e : v2)
	{
		cout << e << ' ';
	}
}

2.3 begin() 和 end()

begin()用于返回第一个有效数据的迭代器

end()用于放回最后一个有效数据的下一位的迭代器

cpp 复制代码
void test1()
{
	vector<int> v{ 1,2,3,4,5,6 };
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << ' ';
		it++;
	}
}

2.4 rbegin() 和 rend()

rbegin()用于返回最后一个有效数据的反向迭代器

rend()用于返回第一个有效数据的前一位的反向迭代器

cpp 复制代码
void test2()
{
	vector<int> v{ 1,2,3,4,5,6 };
	vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend())
	{
		cout << *rit << ' ';
		rit++;
	}
}

reverse_iterator类型的迭代器++向左偏移,--向右偏移

2.5 cbegin(), cend(), crbegin(), crend()

cbegin()和cend():无论对象是否为const对象,返回类型都是const_iterator

crbegin()和crend():无论对象是否为const对象,返回类型都是const_reverse_iterator

2.6 size()

用于返回vector对象中有效数据的个数(元素的个数),它不一定等于容量大小

2.7 capacity()

用于返回vector对象中的容量大小

2.8 empty()

判断vector对象是否为空,空返回true,非空返回false

2.9 reserve()

用于请求更改将容量改为n,当n大于当前容量时,该函数会导致容器重新分配其存储,并将容量增加到n并拷贝原数据,释放原空间;其他情况下(n小于等于当前容量),该函数不会导致容量重新分配。

cpp 复制代码
void test10()
{
	size_t sz;
	vector<int> v;
	v.reserve(100);
	sz = v.capacity();
	//一次性开满,可以减少频繁扩容带来的损耗;
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
			cout << &v[0] << endl;//每次扩容都是异地扩容
		}
	}
}

2.10 resize()

用于调整vector对象有效数据的个数至n个;

n小于当前的size时,有效数据减少至前n个,超出部分删除(并销毁);

n大于当前的size时,通过尾插来将有效数据增加至n个,将新数据初始化为val;

n大于当前的capacity时,会自动重新分配容量。

cpp 复制代码
void test3()
{
	vector<int> v(9);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.empty() << endl;
	v.clear();
	cout << v.empty() << endl;
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	v.resize(5);//默认0填充
	v.reserve(16);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	for (int e : v)
	{
		cout << e << ' ';
	}
}

2.11 shrink_to_fit()

用于请求将容器减少至其有效数据个数的大小,可能会导致空间重新分配

cpp 复制代码
void test11()
{
	vector<int> v = { 0,1,2,3,4,5,6,7,8,9 };
	cout << v.size() << ' ' << v.capacity() << endl;
	v.reserve(19);
	cout << v.size() << ' ' << v.capacity() << endl;
	cout << &v[0] << endl;
	//请求缩小容量以适应其大小
	v.shrink_to_fit();
	cout << v.size() << ' ' << v.capacity() << endl;
	cout << &v[0] << endl;
}

2.12 operator[]

用于通过下标进行访问,返回引用

cpp 复制代码
void test12()
{
	//[]访问
	vector<int> v(10);
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << ' ';
	}
	cout << endl;
	for (int i = 0; i < v.size(); i++)
	{
		v[i] = i;
	}
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << ' ';
	}
}

2.13 at()

用于通过小标进行访问,返回引用

与operator[]的区别:operator[]使用assert暴力检查越界情况,at越界会抛出out_of_range异常

cpp 复制代码
void test13()
{
	//at
	vector<int> v(10);
	for (int i = 0; i < v.size(); i++)
	{
		cout << v.at(i) << ' ';
	}
	cout << endl;
	for (int i = 0; i < v.size(); i++)
	{
		v.at(i) = i;
	}
	for (int i = 0; i < v.size(); i++)
	{
		cout << v.at(i) << ' ';
	}
}

2.14 front() 和 back()

front:返回第一个有效数据的引用(不能对空vector使用front)

back:返回最后一个有效数据的引用(不能对空vector使用back)

cpp 复制代码
void test14()
{
	vector<int> v = { 1,2,3,4,5 };
	//front访问
	cout << v.front() << endl;
	//改变front返回的对象
	v.front() = 11;
	cout << v.front() << endl;
	//back访问
	cout << v.back() << endl;
	//改变back返回的对象
	v.back() = 55;
	cout << v.back() << endl;
	//空容器内使用front和back是未定义行为
}

2.15 data()

返回一个直接指针,该指针指向vector对象内部用于存储数据的内存数组,即指向第一个有效数据

cpp 复制代码
void test15()
{
	vector<int> v = { 1,2,3 };
	//data返回数组第一个元素的指针
	cout << v.data() << endl;
	cout << &v[0] << endl;
	*v.data() = 11;
	cout << *v.data() << endl;
}

2.16 assign()

重新分配新的内容,覆盖原有的数据,并相应修改其大小

cpp 复制代码
void test16()
{
	vector<int> v = { 1,2,3,4,5 };
	vector<int> v1 = { 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 };
	cout << v.capacity() << endl;
	cout << v.size() << endl << endl;
	cout << v1.capacity() << endl;
	cout << v1.size() << endl << endl;
	//范围分配新内容
	v1.assign(v.begin() + 2, v.end());
	cout << v1.capacity() << endl;
	cout << v1.size() << endl;
	for (auto e : v1)
	{
		cout << e << ' ';
	}
	cout << endl << endl;
	//n个元素作为新内容
	v1.assign(16, 99);
	cout << v1.capacity() << endl;
	cout << v1.size() << endl;
	for (auto e : v1)
	{
		cout << e << ' ';
	}
}

2.17 push_back() 和 pop_back()

push_back:用于尾插数据

pop_back:用于尾删数据

cpp 复制代码
void test17()
{
	//push_back
	vector<int> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	for (auto e : v)
	{
		cout << e << ' ';
	}
	//pop_back
	while (!v.empty())
	{
		v.pop_back();
	}
	cout << endl << v.empty() << endl;
}

2.18 insert()

用于在pos位置插入数据

cpp 复制代码
template <class t>
void print(vector<t>& v)
{
	for (auto e : v)
	{
		cout << e << ' ';
	}
	cout << endl;
}
void test18()
{
	//insert
	vector<int> v = { 0,1,2,3,4,5,6,7,8,9 };
	//iterator insert (iterator position, const value_type& val);--在迭代器指向的位置插入,右边数据右移
	cout << *v.insert(v.begin() + 5, 55) << endl;//放回该位置的迭代器
	print(v);
	// void insert (iterator position, size_type n, const value_type& val);--在迭代器位置开始插入n个数据,其他数据右移
	v.insert(v.begin() + 3, 3, 666);
	print(v);
	//template <class inputiterator>//--函数模板--迭代器指定范围插入
	//void insert(iterator position, inputiterator first, inputiterator last);
	list<int> ls;
	for (int i = 0; i < 5; i++)
	{
		ls.push_back(i + 30);
	}
	v.insert(v.begin() + 8, ls.begin(), ls.end());
	print(v);
	
	vector<int> v1 = { 1,2,3,4,5 };
	vector<int>::iterator it = v1.begin();
	//迭代器失效问题
	//v1.insert(it, 2);
	//cout << *it << endl;
	it = v1.insert(it, 2);
	cout << *it << endl;
}

2.19 erase()

用于删除部分数据

cpp 复制代码
void test19()
{
	vector<int> v = { 0,1,2,3,4,5 };
	//iterator erase (iterator position);
	//返回一个迭代器,指向元素的新位置,该元素紧跟在函数调用擦除的最后一个元素之后。
	cout << *v.erase(v.begin() + 2) << endl;
	print(v);

	//范围erase
	//iterator erase (iterator first, iterator last);
	cout << *v.erase(v.begin(), v.begin() + 3) << endl;
	print(v);
}

2.20 swap()

用于交换数据

cpp 复制代码
void test21()
{
	//swap
	vector<int> v1 = { 1,2,3 };
	vector<int> v2 = { 4,5,6 };
	v1.swap(v2);
	print(v1);//4,5,6
	print(v2);//1,2,3
}

2.21 clear()

清除所有数据

cpp 复制代码
void test22()
{
	//clear
	vector<int> v = { 1,2,3 };
	v.clear();
	cout << v.empty() << endl;
}

2.22 emplace()

用于在指定位置构造并插入新数据,它通过将传递的参数转发给构造函数来实现新数据的就地构造。若插入后大小超出当前容量,则会发生自动重新分配存储空间。在向量的任意位置插入数据会导致后续数据的移动,因此相较于其他序列容器,效率较低。

在C++中,选择使用emplace而非insert的情况主要有以下几点:

  1. 构造新对象:当你需要在容器中插入一个新对象,并且希望通过传递构造参数来直接在容器中构造该对象时,使用emplace是更合适的选择。emplace允许直接传递构造函数的参数,而不需要先创建对象再插入。

  2. 避免不必要的拷贝或移动:使用insert时,通常需要先创建一个对象,然后将其拷贝或移动到容器中。emplace则可以避免这种额外的拷贝或移动操作,因为它在容器中直接构造对象。

  3. 性能考虑:在性能敏感的场合,尤其是当插入的对象较大或复杂时,使用emplace可以减少不必要的开销,从而提高性能。

  4. 支持可变参数:如果你需要插入的对象的构造函数接受可变数量的参数,emplace可以直接转发这些参数,而insert则不支持这种灵活性。

cpp 复制代码
void test24()
{
	//emplace
	vector<int> v = { 0,1,2,3,4,5 };
	for (int i = 0; i < v.size(); i++)
	{
		cout << &v[i] << endl;
	}
	auto it = v.emplace(v.begin() + 3, 100);
	print(v);
	for (int i = 0; i < v.size(); i++)
	{
		cout << &v[i] << endl;
	}
	cout << *it << endl;
}

2.23 emplace_back

用于末尾构造并插入,与push_back不同, emplace_back直接在容器中构造对象,而不是先构造对象再将其拷贝或移动到容器中。这可以提高效率,特别是对于需要进行昂贵拷贝或移动操作的对象。

2.24 get_allocator

主要用于获取与容器关联的分配器(allocator),分配器的主要职责是负责动态内存的分配和释放,使得 C++ 标准库的容器能够高效地管理内存。

cpp 复制代码
int main()
{
	std::vector<int> myvector;
	int* p;
	unsigned int i;

	// allocate an array with space for 5 elements using vector's allocator:
	p = myvector.get_allocator().allocate(5);

	// construct values in-place on the array:
	for (i = 0; i < 5; i++)
		myvector.get_allocator().construct(&p[i], i);

	std::cout << "The allocated array contains:";
	for (i = 0; i < 5; i++) 
		std::cout << ' ' << p[i];
	std::cout << '\n';

	// destroy and deallocate:
	for (i = 0; i < 5; i++) 
		myvector.get_allocator().destroy(&p[i]);
	myvector.get_allocator().deallocate(p, 5);

	return 0;
}

2.25 关系运算符重载(非成员函数)

用于比较

2.26 swap()(非成员函数)

2.27 vector<bool>

vector<bool>是 C++ 标准模板库(STL)中提供的一个特殊化的std::vector容器。与其他类型的 vector不同,vector<bool>并不直接存储布尔值,而是采用了一种特化的实现方式,以节省内存使用。

具体来说,vector<bool>会使用位压缩的方式,将多个布尔值压缩存储为单个位(bit),即每一个布尔值只占用 1 位,而不是通常情况下的 1 字节(8 位)。这一特性使得 vector<bool> 的内存使用更加高效,当存储大量布尔值时,可以显著减少内存占用。

然而,这种特殊化也带来了一些不便,例如:

  1. vector<bool> 的元素类型是一个代理对象(proxy object),而不是真正的 bool 类型。这种实现方式会导致某些常见的操作(如取地址)变得复杂。

  2. 由于使用位处理,vector<bool> 的访问性能可能比普通的 vector<T> 低,因为每次访问都需要进行一些位运算。

在需要存储布尔值的情况下,如果对内存效率敏感并且接受其带来的不便(如性能和使用复杂性),可以使用 vector<bool>。否则,通常建议使用 std::vector<char> 或 std::vector<uint8_t>等其他类型,以保证更方便的语义和更好的性能。

3.vector扩容问题

测试代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。

这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。

reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。

resize在开空间的同时还会进行初始化,影响size。

cpp 复制代码
void test8()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
			cout << &v[0] << endl;//每次扩容都是异地扩容
		}
	}
}


void test10()
{
	size_t sz;
	vector<int> v;
	v.reserve(100);
	sz = v.capacity();
	//一次性开满,可以减少频繁扩容带来的损耗;
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
			cout << &v[0] << endl;//每次扩容都是异地扩容
		}
	}
}

4.迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了 ,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)

vector可能引起迭代器失效的操作有:

1.会引起其底层空间改变的操作 ,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back,emplace,emplace_back等。

2.指定位置元素的删除操作--erase:erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了

迭代器失效的解决办法:在使用前,对迭代器重新赋值即可。

cpp 复制代码
void test20()
{
	vector<int> v = { 0,1,2,3,4,5 };
	vector<int>::iterator it = v.begin();
	//迭代器失效问题
	//v.erase(it);
	//cout << *it << endl;

	it = v.erase(it);
	cout << *it << endl;
}

5.内存检查

系统对内存的检查是一种抽查机制,动态开辟的通常在delete/free的时候检查,所以没有delete/free的时候越界使用可能暴漏不出来问题

6.find算法

vector自生没有find,不过算法库里面有find函数模板

7.= default

= default 是 C++11 中引入的一种特殊语法,用于指示编译器生成一个类的默认构造函数、拷贝构造函数、拷贝赋值运算符、移动构造函数或移动赋值运算符 。通过使用 = default,程序员可以显式指定希望编译器生成的函数,而不是手动实现这些函数。

8.调用问题

解决关键是:编译器的选择问题

解决1:

解决2:

9.initializer_list

std::initializer_list 是 C++11 引入的一个标准库类模板,用于支持列表初始化(List Initialization)和统一初始化。它允许你使用花括号 {} 语法来初始化具有多个元素的对象,提供了一种简单且易于使用的方式来创建和传递多个值。

std::initializer_list 实际上是一个轻量级的对象,可以承载一个常量数组的引用和大小信息。它常用在构造函数和函数参数中,使得我们能够方便地传递一组值。

cpp 复制代码
#include <iostream>  
#include <initializer_list>  

void printValues(std::initializer_list<int> values)
{  
    for (auto value : values) 
    {  
        std::cout << value << " ";  
    }  
    std::cout << std::endl;  
}  

int main() 
{  
    printValues({10, 20, 30, 40}); // 传递initializer_list  
    return 0;  
}
cpp 复制代码
#include <iostream>  
#include <initializer_list>  

class MyVector 
{  
public:  
    MyVector(std::initializer_list<int> values) 
{  
        for (auto value : values) 
        {  
            // 处理每个传入的值  
            std::cout << value << " ";  
        }  
        std::cout << std::endl;  
    }  
};  

int main() 
{  
    MyVector vec = {1, 2, 3, 4, 5}; // 使用initializer_list初始化  
    return 0;  
}

注意:

  1. std::initializer_list 只能用于常量对象(const)

2.使用 std::initializer_list 可以方便地进行传参和初始化。

  1. 支持不同类型的容器(如std::vector,std::array 等)支持列表初始化。

10.vector的部分模拟实现

cpp 复制代码
#pragma once
#include <string>
#include <vector>
#include <assert.h>
#include <iostream>
#include <algorithm>
#include <list>

namespace myVector
{
	template <class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		typedef T* reverse_iterator;
		typedef const T* const_reverse_iterator;
		
		//迭代器
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin()const
		{
			return _start;
		}
		const_iterator end()const
		{
			return _finish;
		}
		const_iterator cbegin() const
		{
			return _start;
		}
		const_iterator cend() const
		{
			return _finish;
		}
		

		//迭代器区间初始化
		//函数模板--目的是支持任意容器可以进行迭代器区间初始化
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		//这里的缺省值为什么这么写?
		//因为T可能是自定义类型,无参构造并引用匿名对象
		//对于内置类型:
		//c以前的构造: int i = 0;//0
		//c++现在可以: int j(1);//1
		//                      int k = int();//0
		//                      int x = int(2);//2
		//c++内置类型进行了升级,也有构造,为了兼容这样的场景:
		//当模板函数参数可以是自定义类型或者内置类型,给缺省值的形式进行统一
		vector(size_t n, const T& val = T())
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}
		//vector<int> v = {1,2,3,4,5};
		vector(std::initializer_list<T> il)
		{
			reserve(il.size());
			for (auto e : il)
			{
				push_back(e);
			}
		}

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

		vector(const vector<T>& v)
		{
			//提前扩容,减少扩容次数
			reserve(v.capacity());
			for (auto e : v)
			{
				push_back(e);
			}
		}

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

		//利用传值会进行拷贝再直接交换,局部变量v会自动销毁
		//现代写法
		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

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

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t oldsize = size();
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy是浅拷贝
					//memcpy(tmp, _start, sizeof(T) * oldsize);
					//改为深拷贝
					for (size_t i = 0; i < oldsize; i++)
					{
						tmp[i] = _start[i];//赋值是深拷贝
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = oldsize + _start;
				_end_of_storage = _start + n;
			}
		}

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

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

		T& operator[](size_t i)
		{
			assert(i < size() && i >= 0);
			return *(_start + i);
		}
		const T& operator[](size_t i) const
		{
			assert(i < size() && i >= 0);
			return *(_start + i);
		}

		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}
			*_finish = x;
			++_finish;
		}
		void pop_back()
		{
			assert(size() > 0);
			--_finish;
		}
		iterator insert(iterator pos, const T& x)
		{
			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;
		}
		void erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			iterator it = pos + 1;
			while (it != _finish)
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;
		}

	private:
		iterator _start;//有效数据的起始位置,闭区间
		iterator _finish;//最后的有效数据的下一位,开区间
		iterator _end_of_storage;//这段容量的最后位置的下一个,开区间
	};
}
相关推荐
杨荧12 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
白子寰18 分钟前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_0123 分钟前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj29 分钟前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT30 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
为将者,自当识天晓地。32 分钟前
c++多线程
java·开发语言
-Even-33 分钟前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus
小政爱学习!34 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
神奇夜光杯1 小时前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长