std::array - Dynamic Memory, no Thanks

Contents[Show]

std::array combines the best from two worlds. At one hand, std::array has the size and efficiency of a C array; at the other hand, std::array has the interface of a std::vector. 

 

std::array has a unique characteristic among all sequential containers of the Standard Template Library. You can not adjust it size during runtime. There are special rules for its initialization.

The initialization

You have to keep the rule for aggregate initialization in mind:

  • std::array<int,10> arr: The 10 elements are not initialized.
  • std::array<int,10>arr{}. The 10 elements are value-initialized.
  • std::array<int,10>arr{1,2,3,4): The remaining elements are value-initialized.

 As a sequential container, std::array supports the index access.

Index access

std::array arr supports the index access in three ways.

  • arr[n-1]: Access to the nth element without a check of the array boundaries.
  • arr.at(n-1):Access to the nth element with a check of the array boundaries. Eventually, a std::range_error exception is thrown.
  • std::get<n-1>(arr):Access to the nth element with a check of the array boundaries at compile time. The syntax is according to std::tuple.

std::get<n>(arr) shows the relationship of std::array with std::tuplestd::array is a homogeneous container of fixed size; std::tuple is a heterogeneous container of fixed size.

I claimed that the C++ array is as memory efficient as a C array. The proof is still missing.

Memory efficiency

My small program compares the memory efficiency of a C array, a C++ array, and a std::vector.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// sizeof.cpp

#include <iostream>
#include <array>
#include <vector>
 
 
int main(){
  
  std::cout << std::endl;
  
  std::cout << "sizeof(int)= " << sizeof(int) << std::endl;
  
  std::cout << std::endl;
  
  int cArr[10]= {1,2,3,4,5,6,7,8,9,10};
  
  std::array<int,10> cppArr={1,2,3,4,5,6,7,8,9,10};
  
  std::vector<int> cppVec={1,2,3,4,5,6,7,8,9,10};
  
  std::cout << "sizeof(cArr)= " << sizeof(cArr) << std::endl;  
  
  std::cout << "sizeof(cppArr)= " << sizeof(cppArr) << std::endl;
  
  std::cout << "sizeof(cppVec) = "   << sizeof(cppVec) + sizeof(int)*cppVec.capacity() << std::endl;
  std::cout << "               = sizeof(cppVec): " << sizeof(cppVec) << std::endl;
  std::cout << "               + sizeof(int)* cppVec.capacity(): "   << sizeof(int)* cppVec.capacity() << std::endl;

  std::cout << std::endl;
  
}

 

The numbers speak a clear language.

 

sizeof

Both the C array (line 22) and the C++ array (line 24) take 40 bytes. That is exactly sizeof(int)*10. In opposite to them std::vector needs additional 24 bytes (line 27) do manage its data on the heap. cppVec.capacity() is the number of elements a std::vector cppVec can have without acquiring new memory. I described the details of the memory management of std::vector and std::string in the post Automatic memory management of the STL containers.

Before I complete the picture and show the example I want to explicitly emphasis. The great value of a std::array in opposite to a  C array is that std::array knows it size.

std::array in action

One additional value of a std::array in comparison to a C array is it that a std::array feels like a std::vector.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// array.cpp

#include <algorithm>
#include <array>
#include <iostream>

int main(){

  std::cout << std::endl;

  // output the array
  std::array <int,8> array1{1,2,3,4,5,6,7,8};
  std::for_each( array1.begin(),array1.end(),[](int v){std::cout << v << " ";});

  std::cout << std::endl;

  // calculate the sum of the array by using a global variable
  int sum = 0;
  std::for_each(array1.begin(), array1.end(),[&sum](int v) { sum += v; });
  std::cout << "sum of array{1,2,3,4,5,6,7,8}: " << sum << std::endl;

  // change each array element to the second power
  std::for_each(array1.begin(), array1.end(),[](int& v) { v=v*v; });
  std::for_each( array1.begin(),array1.end(),[](int v){std::cout << v << " ";});
  std::cout << std::endl;

  std::cout << std::endl;

}

 

Therefore, you can output array1 in line 13 with a lambda-function and the range-based for-loop. By using the summation variable sum in line 19 you can sum up the elements of the std::array. The lambda-function in line 23 takes its arguments by reference and can therefore map each element to its square. Really nothing special, but we are dealing with a std::array.

And here is the output of the program.

array

For clarification

With C++11 we have the free function templates std::begin and std::end returning iterators for a C array. So a C array is quite comfortable and safe to use with these function templates because you have not to remember its size.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// cArray.cpp

#include <algorithm>
#include <iostream>

int main(){

  std::cout << std::endl;

  // output the array
  int array1[] = { 1, 2, 3, 4, 5, 6 ,7, 8};
  std::for_each( std::begin(array1), std::end(array1), [](int v){ std::cout << v << " "; });

  std::cout << std::endl;

  // calculate the sum of the array by using a global variable
  int sum = 0;
  std::for_each(std::begin(array1), std::end(array1), [&sum](int v) { sum += v; });
  std::cout << "sum of array{1, 2, 3, 4, 5, 6, 7, 8}: " << sum << std::endl;

  // change each array element to the second power
  std::for_each(std::begin(array1), std::end(array1), [](int& v) { v=v*v; });
  std::for_each(std::begin(array1), std::end(array1), [](int v){ std::cout << v << " "; });
  std::cout << std::endl;

  std::cout << std::endl;
  
}

 

Of course, the result is the same.

What's next?

This post was concise. In the next post I will have a closer look at one of the prominent C++11 features: move semantic.


 

 

 

 

 

 

 

 

 

title page smalltitle page small Go to Leanpub/cpplibrary "What every professional C++ programmer should know about the C++ standard library".   Get your e-book. Support my blog.

 

 


 

Tags: memory

Comments   

0 #1 Future 2016-12-20 08:34
I agree with you that array should be the container of choice in most cases in which the required size is known at compile time. Just one little remark. Swapping two array's might be slower than swapping two vectors. This is because swapping vectors means swapping two pointers, while each pair of elements has to be swapped in the case of the array.
Quote
+1 #2 minirop 2016-12-20 16:20
std::get() does bound checking, but at compile time.
Quote
-1 #3 Rainer 2016-12-20 19:18
Quoting Future:
I. Swapping two array's might be slower than swapping two vectors. This is because swapping vectors means swapping two pointers, while each pair of elements has to be swapped in the case of the array.

Good point. My next post compares the performane of copy and move initialization including std::array and std::vector.
Quote
0 #4 Rainer 2016-12-20 19:22
Quoting minirop:
std::get() does bound checking, but at compile time.

Good point. I will add it.
Quote
0 #5 whatever 2016-12-23 07:35
"std::arrayarr{}. The 10 elements are default initialized."
this is incorrect. The elements are value-initialized here, and in the following line.
Quote
0 #6 Rainer Grimm 2016-12-23 20:40
Quoting whatever:
"std::arrayarr{}. The 10 elements are default initialized."
this is incorrect. The elements are value-initialized here, and in the following line.

Thanks for the clarification. I will change it.
Quote
0 #7 Dima Breeze 2016-12-25 10:28
> The great value of a std::array in opposite to a C array is that std::array knows it size.

C array doesn't know its size, but std::extent::value gives you C-array size at compile time
Quote
0 #8 Rainer Grimm 2016-12-25 20:51
Quoting Dima Breeze:
> The great value of a std::array in opposite to a C array is that std::array knows it size.

C array doesn't know its size, but std::extent::value gives you C-array size at compile time

Thanks a lot, Dima. I know the type-traits but I was not aware of this function template.
Quote
0 #9 Denis 2017-01-25 05:43
Does std::array have time penalty to get element by index/iterator comparison to C-array, std::vector? May be create some test snippets?
Quote
0 #10 fasttechupdates 2017-01-25 13:44
What's up, I check your blogs regularly. Your story-telling
style is awesome, keep doing what you're doing!
Quote

Add comment


My Newest E-Book

Latest comments

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 91

All 333382

Currently are 174 guests and no members online