STL-02-array使用及其源码剖析

array 容器是 C++ 11 标准中新增的序列容器,简单地理解,它就是在 C++ 普通数组的基础上,添加了一些成员函数和全局函数。

之前我在思考,STL为什么要多出这个容器呢?直接用数组它不香吗??它不快吗?非要搞出这么个玩意。后来我想明白了,我觉得它就是想要使用STL里面的算法。

先把它用起来吧。

首先需要引用:

#include <array>

array也就是数组嘛,所以它和我们常用的数组一样比如:int a[10],它表示10个整型的元素;array 容器和数组一样,它的大小也是固定的,无法动态的扩展或收缩。

std::array<int,10> a;这个和int a[10];一样。

但是std::array<int,10> a;和int a[10];一样,都没有默认初始化。

std::array<int,10> a{}

这代表默认初始化为0.

如下测试:

在这里插入图片描述
默认初始化为0.

再看另外的测试:

在这里插入图片描述
从结果可以看出和数组特性一模一样。

现在看看随机访问:

在这里插入图片描述

其中我比较喜欢的一个数可以直接拿出它的个数,不想数组一样sizeof(a)/sizeof(a[0]),ZTM麻烦,如下
在这里插入图片描述
赋值与交换
使用array的一个好处就是可以将一个相同类型的array对象赋值给另一个对象,array中的元素将会依次进行复制,因此,在赋值之后,两个array具有相同的元素,但需要保证两个array具有相同的元素类型以及大小。但对于一般数组,则不能这样做:

array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
array<int, 5> arr2 = { 5, 4, 3, 2, 1 };
array<int, 5> arr3 = arr1;                  // arr3 包含:1 2 3 4 5
arr3 = arr2;                                // arr3 包含:5 4 3 2 1 
 array<int, 10> a;         // arr中元素的值是未定义的
 

在这里插入图片描述
不能使用初始化列表来向array赋值

array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
// ERROR: arr1 = { 1, 2, 3 }; 不能使用初始化列表来向array赋值
 

可以使用array的成员函数fill()来将array中的元素赋为相同的值
在这里插入图片描述

下面是一些常用的函数:

成员函数功能
begin()返回指向容器中第一个元素的随机访问迭代器。
end()返回指向容器最后一个元素之后一个位置的随机访问迭代器,通常和 begin() 结合使用。
rbegin()返回指向最后一个元素的随机访问迭代器。
rend()返回指向第一个元素之前一个位置的随机访问迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
size()返回容器中当前元素的数量,其值始终等于初始化 array 类的第二个模板参数 N。
max_size()返回容器可容纳元素的最大数量,其值始终等于初始化 array 类的第二个模板参数 N。
empty()判断容器是否为空,和通过 size()==0 的判断条件功能相同,但其效率可能更快。
at(n)返回容器中 n 位置处元素的引用,该函数自动检查 n 是否在有效的范围内,如果不是则抛出 out_of_range 异常。
front()返回容器中第一个元素的直接引用,该函数不适用于空的 array 容器。
back()返回容器中最后一个元素的直接应用,该函数同样不适用于空的 array 容器。
data()返回一个指向容器首个元素的指针。利用该指针,可实现复制容器中所有元素等类似功能。
fill(val)将 val 这个值赋值给容器中的每个元素。
array1.swap(array2)交换 array1 和 array2 容器中的所有元素,但前提是它们具有相同的长度和类型。

上面是一些常用的函数。使用方法也有说明。

接下来看看源码:

这个源码是我VS2013下的,在c盘就有,自己可以拿来学习。
详细路径为:C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\array
我直接将解释写在后面吧

注意源码后面我有部分源代码解释。

template<class _Ty,//函数模板,表明类型,如int
	size_t _Size>//表明几个元素
	class array
	{	// fixed size array of values
public:
	enum {_EEN_SIZE = _Size};	// helper for expression evaluator
	typedef array<_Ty, _Size> _Myt;
	typedef _Ty value_type;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	typedef _Ty *pointer;
	typedef const _Ty *const_pointer;
	typedef _Ty& reference;
	typedef const _Ty& const_reference;

	typedef _Array_iterator<_Ty, _Size> iterator;
	typedef _Array_const_iterator<_Ty, _Size> const_iterator;

	typedef _STD reverse_iterator<iterator> reverse_iterator;
	typedef _STD reverse_iterator<const_iterator> const_reverse_iterator;

	void assign(const _Ty& _Value)
		{	// assign value to all elements
		_Fill_n(_Elems, _Size, _Value);
		}

	void fill(const _Ty& _Value)
		{	// assign value to all elements
		_Fill_n(_Elems, _Size, _Value);
		}

	void swap(_Myt& _Other)
		_NOEXCEPT_OP(_NOEXCEPT_OP(_Swap_adl(_Elems[0], _Elems[0])))
		{	// swap contents with _Other
		_Swap_ranges(_STD addressof(_Elems[0]),
			_STD addressof(_Elems[0]) + _Size,
			_STD addressof(_Other._Elems[0]));
		}

	iterator begin() _NOEXCEPT
		{	// return iterator for beginning of mutable sequence
		return (iterator(_STD addressof(_Elems[0]), 0));
		}

	const_iterator begin() const _NOEXCEPT
		{	// return iterator for beginning of nonmutable sequence
		return (const_iterator(_STD addressof(_Elems[0]), 0));
		}

	iterator end() _NOEXCEPT
		{	// return iterator for end of mutable sequence
		return (iterator(_STD addressof(_Elems[0]), _Size));
		}

	const_iterator end() const _NOEXCEPT
		{	// return iterator for beginning of nonmutable sequence
		return (const_iterator(_STD addressof(_Elems[0]), _Size));
		}

	reverse_iterator rbegin() _NOEXCEPT
		{	// return iterator for beginning of reversed mutable sequence
		return (reverse_iterator(end()));
		}

	const_reverse_iterator rbegin() const _NOEXCEPT
		{	// return iterator for beginning of reversed nonmutable sequence
		return (const_reverse_iterator(end()));
		}

	reverse_iterator rend() _NOEXCEPT
		{	// return iterator for end of reversed mutable sequence
		return (reverse_iterator(begin()));
		}

	const_reverse_iterator rend() const _NOEXCEPT
		{	// return iterator for end of reversed nonmutable sequence
		return (const_reverse_iterator(begin()));
		}

	const_iterator cbegin() const _NOEXCEPT
		{	// return iterator for beginning of nonmutable sequence
		return (((const _Myt *)this)->begin());
		}

	const_iterator cend() const _NOEXCEPT
		{	// return iterator for end of nonmutable sequence
		return (((const _Myt *)this)->end());
		}

	const_reverse_iterator crbegin() const _NOEXCEPT
		{	// return iterator for beginning of reversed nonmutable sequence
		return (((const _Myt *)this)->rbegin());
		}

	const_reverse_iterator crend() const _NOEXCEPT
		{	// return iterator for end of reversed nonmutable sequence
		return (((const _Myt *)this)->rend());
		}

	size_type size() const _NOEXCEPT
		{	// return length of sequence
		return (_Size);
		}

	size_type max_size() const _NOEXCEPT
		{	// return maximum possible length of sequence
		return (_Size);
		}

	bool empty() const _NOEXCEPT
		{	// test if sequence is empty
		return (_Size == 0);
		}

	reference at(size_type _Pos)
		{	// subscript mutable sequence with checking
		if (_Size <= _Pos)
			_Xran();
		return (_Elems[_Pos]);
		}

	const_reference at(size_type _Pos) const
		{	// subscript nonmutable sequence with checking
		if (_Size <= _Pos)
			_Xran();
		return (_Elems[_Pos]);
		}

	reference operator[](size_type _Pos)
		{	// subscript mutable sequence
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Size <= _Pos)
			_DEBUG_ERROR("array subscript out of range");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE_RANGE(_Pos < _Size);
 #endif /* _ITERATOR_DEBUG_LEVEL */

		_Analysis_assume_(_Pos < _Size);

		return (_Elems[_Pos]);
		}

	const_reference operator[](size_type _Pos) const
		{	// subscript nonmutable sequence
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Size <= _Pos)
			_DEBUG_ERROR("array subscript out of range");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE_RANGE(_Pos < _Size);
 #endif /* _ITERATOR_DEBUG_LEVEL */

		_Analysis_assume_(_Pos < _Size);

		return (_Elems[_Pos]);
		}

	reference front()
		{	// return first element of mutable sequence
		return (_Elems[0]);
		}

	const_reference front() const
		{	// return first element of nonmutable sequence
		return (_Elems[0]);
		}

	reference back()
		{	// return last element of mutable sequence
		return (_Elems[_Size - 1]);
		}

	const_reference back() const
		{	// return last element of nonmutable sequence
		return (_Elems[_Size - 1]);
		}

	_Ty *data() _NOEXCEPT
		{	// return pointer to mutable data array
		return (_Elems);
		}

	const _Ty *data() const _NOEXCEPT
		{	// return pointer to nonmutable data array
		return (_Elems);
		}

	__declspec(noreturn) void _Xran() const
		{	// report an out_of_range error
		_Xout_of_range("invalid array<T, N> subscript");
		}

	_Ty _Elems[_Size == 0 ? 1 : _Size];
	};

可以看到这个里面没有分配器(内存管理器),直接用的数组。
其实这源码很简单,就挑出几个吧:
如下伪代码:

首先看:

这个就是存储元素的

_Ty _Elems[_Size == 0 ? 1 : _Size];

它很智能如果是0个元素那么就给它调整为1个,当然不能为0啊,可以这样想,int a[0];这显然是不行的。

还有这一胡片的重定义,需要你花点时间将其对号入座:

typedef array<_Ty, _Size> _Myt;
	typedef _Ty value_type;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	typedef _Ty *pointer;
	typedef const _Ty *const_pointer;
	typedef _Ty& reference;
	typedef const _Ty& const_reference;
reference at(size_type _Pos)
		{	// subscript mutable sequence with checking
		if (_Size <= _Pos)
			_Xran();
		return (_Elems[_Pos]);
		}

首先对访问位置进行判读,如果大于整个数组的大小,就发出异常。
如果没有就放回该位置的引用。所以我们才能有如下操作:
a.at(2) = 100;

同理如下;

	reference operator[](size_type _Pos)
		{	// subscript mutable sequence
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Size <= _Pos)
			_DEBUG_ERROR("array subscript out of range");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE_RANGE(_Pos < _Size);
 #endif /* _ITERATOR_DEBUG_LEVEL */

		_Analysis_assume_(_Pos < _Size);

		return (_Elems[_Pos]);
		}

前面的一堆都是检查,我相信你看到过:array subscript out of range,就是从这里弹出的。最后一行我相信你能看懂,不就一个数组嘛。返回相应的元素。

接着有:

_Ty *data() _NOEXCEPT
		{	// return pointer to mutable data array
		return (_Elems);
		}

可以看出也就是返回了数组的首元素地址,那也就是第一个元素的地址嘛。

iterator begin() _NOEXCEPT
		{	// return iterator for beginning of mutable sequence
		return (iterator(_STD addressof(_Elems[0]), 0));
		}

在比如,这个也就是返回数组的首元素嘛,然后再转化为typedef _Array_iterator<_Ty, _Size> iterator;这种迭代器类型。

所以说这个是最简单的。

接下来看看它加入容器的好处:
在这里插入图片描述
我们可以轻松的使用STL算法。

看源代码一定要看它的实现思路,原理,不要钻牛角尖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

发如雪-ty

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

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

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

打赏作者

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

抵扣说明:

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

余额充值