sizeof

std::array – Dynamic Memory, no Thanks

std::array combines the best of two worlds. On the one hand, std::array has the size and efficiency of a C array; on 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 its 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 ten elements are not initialized.
  • std::array<int,10>arr{}. The ten 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 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 the nth element by checking the array boundaries. Eventually, a std::range_error exception is thrown.
  • std::get<n-1>(arr): Access the nth element by checking 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.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Generic Programming (Templates) with C++": October 2024
  • "Embedded Programming with Modern C++": October 2024
  • "Clean Code: Best Practices for Modern C++": March 2025
  • Do you want to stay informed: Subscribe.

     

    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 precisely sizeof(int)*10. In opposite to them, std::vector needs additional 24 bytes (line 27) to 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 emphasize it explicitly: The great value of a std::array in opposition to a  C array is that std::array knows it size.

    std::array in action

    One additional value of a std::array compared to a C array is 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. 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. 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 do 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 look closely at one of the prominent C++11 features: move semantic.

     

     

     

     

    Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.

    Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Modernes C++ GmbH

    Modernes C++ Mentoring (English)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 176 5506 5086
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *