C++11 std::array

  • std::array是在C++ 11标准中增加的STL容器,它的设计目的是提供与原生数组类似的功能与性能。正因此,使得std::array有很多与其他容器不同的特殊之处,比如:
  • std::array的元素是直接存放在实例内部,而不是在堆上分配间;
  • std::array的大小必须在编译期确定。
  • std::array的构造函数、析构函数和赋值操作符都是编译器隐式声明的……

  • 底层原理
  • 1. std::array
    • 1. 1 常用函数
    • 1. 2 构造函数
  • 2. size、max_size、empty
  • 3. fill、data、swap


底层原理

   std::array底层是一段连续的固定大小的内存,实现是在struct中定义数组作为成员变量:

std::array<int, 5> arr = {1, 2, 3, 4, 5};
  • 上述代码中,对象arr 存储在栈中,对象中包含一个在栈上定义的数组用于存储元素。容器的大小必须在编译期确定。
  • 源码中std::array定义如下。
  • _M_elems是定义的数组用于存储元素。
  template<typename _Tp, std::size_t _Nm>
    struct array
    {
      typedef _Tp 	    			      value_type;
      typedef value_type*			      pointer;
      typedef const value_type*                       const_pointer;
      typedef value_type&                   	      reference;
      typedef const value_type&             	      const_reference;
      typedef value_type*          		      iterator;							// 迭代器
      typedef const value_type*			      const_iterator;
      typedef std::size_t                    	      size_type;
      typedef std::ptrdiff_t                   	      difference_type;
      typedef std::reverse_iterator<iterator>	      reverse_iterator;			// 反向迭代器
      typedef std::reverse_iterator<const_iterator>   const_reverse_iterator;

      // Support for zero-sized arrays mandatory.
      typedef _GLIBCXX_STD_C::__array_traits<_Tp, _Nm> _AT_Type;				// *			
      typename _AT_Type::_Type                         _M_elems;				// 定义的数组用于存储元素
	 ...
  • 上述源码中,__array_traits的定义有两个版本,模板申明单参数(type)和双参数(typesize),便实现size == 0array的原理。
  template<typename _Tp, std::size_t _Nm>			// _Tp为元素类型、_Nm为容器大小size
    struct __array_traits
    {
      typedef _Tp _Type[_Nm];

      static constexpr _Tp&
      _S_ref(const _Type& __t, std::size_t __n) noexcept
      { return const_cast<_Tp&>(__t[__n]); }

      static constexpr _Tp*
      _S_ptr(const _Type& __t) noexcept
      { return const_cast<_Tp*>(__t); }
    };

 template<typename _Tp>								// _Tp为元素类型,容器大小默认为0
   struct __array_traits<_Tp, 0>
   {
     struct _Type { };

     static constexpr _Tp&
     _S_ref(const _Type&, std::size_t) noexcept
     { return *static_cast<_Tp*>(nullptr); }

     static constexpr _Tp*
     _S_ptr(const _Type&) noexcept
     { return nullptr; }
   };

1. std::array

1. 1 常用函数

at				通过下标获取对应元素引用
back			尾元素引用
begin   		iterator
cbegin			const iterator
cend			const iterator
crbegin			iterator reverse iterator
crend			iterator reverse reverse
data			底层数组
empty			容器是否为空
end				iterator

fill			赋值
front  			头元素引用
max_size
operator[]		通过下标获取元素引用
rbegin			reverse iterator
rend			reverse iterator
size
swap

1. 2 构造函数

   std::array作为聚合类,可以通过为类(defaultcopymove)隐式定义的函数来进行构造容器对象, 或使用 initializer lists 来构造对象:

  • I. default-initialization:
    a: 对于类类型,使用类的默认构造;
    b: 对于默认类型如int,元素将保持未初始化状态;
    c: 若array对象为static的,则元素0初始化。
std::array<int, 10> static_arr;		// 默认初始化,静态对象
int main() {
    std::array<int, 10> arr;
    
    for(auto& i:arr)            
        cout << i << " ";
    cout << endl;

    for(auto& i:static_arr)  		// 打印静态对象array中元素
        cout << i << " ";
    cout << endl;

    return 0;
}

0 0 0 0 4197872 0 4197168 0 226809856 32765
0 0 0 0 0 0 0 0 0 0

  • 可以看出在栈中的局部变量 arr 中元素为int 随机值。
  • 静态变量static_arr内部元素进行了0初始化。

  • II. copy/move initialization: 将类型、大小相同的array对象的元素 复制/移动 到构造的array中。
int main() {
    std::array<int,3> arr = {1,2,3};    // initialized as:   {1,2,3}
    std::array<int,3> arr_copy = arr;   // copy:             {1,2,3}

    return 0;
}

  • III. initializer list:list中的元素个数小于array.size, 那么对于剩余元素将进行初始化(类类型为 默认初始化、 普通类型为0初始化)。
int main() {
    // initialized as:   {1,2,3,0,0}
    std::array<int,5> arr = {1,2,3};    
    
    return 0;
}

2. size、max_size、empty

  • size(),返回容器中元素个数。
  • max_size(),返回容器可以容乃的最大元素个数,返回值与size()一样,总是等于第二个模板参数_Nm
  • empty(),返回容器是否为空,即容器size是否为0。
constexpr size_type size() noexcept;		// size 函数原型
constexpr size_type max_size() noexcept;	// max_size 
constexpr bool empty() noexcept;			// empty

   测试代码:

int main () {
    std::array<int,5> arr_int;
    std::cout << "size of arr_int: " << arr_int.size() << std::endl;
    std::cout << "max_size of arr_int: " << arr_int.max_size() << '\n';
    std::cout << "sizeof(arr_int): " << sizeof(arr_int) << std::endl;
    std::cout << "arr_int " << (arr_int.empty() ? "is empty" : "is not empty") << '\n';

    cout << endl;
    std::array<int,0> arr_empty;
    std::cout << "arr_empty " << (arr_empty.empty() ? "is empty" : "is not empty") << '\n';
    std::cout << "sizeof(arr_empty): " << sizeof(arr_empty) << std::endl;

    return 0;
}

size of arr_int: 5
max_size of arr_int: 5
sizeof(arr_int): 20
arr_int is not empty

aarr_empty is empty
sizeof(arr_empty): 1

  • 可以看出,arr_empty使用array模板类创建的是一个空类,所有其实例化对象的sizeof为1。
  • c++中,空类和空结构体的大小是1。

3. fill、data、swap

  • fill(),将容器中所有元素值设置为val
  • data(),返回指向容器中第一个元素的指针,后续可以通过指针偏移访问其他元素。
  • swap(),当前容器与,另一个相同类型、相同大小的array交换容器中所有元素,如果类型或大小不同,则无法通过编译。
void fill(const value_type& val);				// fill 函数原型

      value_type* data() noexcept;				// data
const value_type* data() const noexcept;	
												// swap
void swap (array& x) noexcept(noexcept(swap(declval<value_type&>(),declval<value_type&>())));

   测试代码:

int main () {
    std::array<int,3> arr_first;
    arr_first.fill(9);								// fill(), arr_first:9 9 9

    std::array<int,3> arr_second = {10,100,1000};
    arr_first.swap(arr_second);						// 交换俩arr对象中元素

    cout << "arr_first element: ";      			// data()函数获取头元素指针 
    int* p = arr_first.data();						// 通过指针偏移打印 arr_first 元素
    for(int i=0; i<arr_first.size(); ++i)
        cout << *(p+i) << " ";

    return 0;
}

arr_first element: 10 100 1000

你可能感兴趣的:(C++,STL)