tinkering with c++ — replacing boost array with standard c++ array

Boost does more than provide a collection of advanced libraries for the C++ language. Many of Boost’s authors are also part of the C++ standards committee. Thus, many new features being considered for the C++ standard are implemented here first. One of those features that has now migrated into the official standard is boost::array, which as of C++11 is now std::array. The page for boost::array has the following line on its documentation front page:

Update: std::array is (as of C++11) part of the C++ standard. The differences between boost::array and std::array are minimal. If you are using C++11, you should consider using std::array instead of boost::array.

The following code shows some of the ways this container is used. If you change the #include <array> to <boost/array>, as well as the corresponding using statement, then it will compile and execute the same.

#include <array>#include <algorithm>#include <iostream>using std::array;using std::cout;using std::sort;using std::string;int main() {array<int, 10> iarray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};cout << "Array of integers:" << "\n";for (const auto value : iarray) {cout << "Integer array value: " << value << "\n";}cout << "\n" << "Array of standard strings:" << "\n";array<string, 10> sarray ={"one","two","three","four","five","six","seven","eight","nine","ten"};for (const auto value : sarray) {cout << "String array value: " << value << "\n";}cout << "\n" << "Array of sorted strings:" << "\n";sort(sarray.begin(), sarray.end());for (const auto value : sarray) {cout << "String array value: " << value << "\n";}return 0;}

Compiling It

Compilation is a simple one liner.

g++ -std=c++20 array-test.cpp -o array-test

Sample Run

Here’s what happens when we run it.

~ ./array-test Array of integers:Integer array value: 1Integer array value: 2Integer array value: 3Integer array value: 4Integer array value: 5Integer array value: 6Integer array value: 7Integer array value: 8Integer array value: 9Integer array value: 10Array of standard strings:String array value: oneString array value: twoString array value: threeString array value: fourString array value: fiveString array value: sixString array value: sevenString array value: eightString array value: nineString array value: tenArray of sorted strings:String array value: eightString array value: fiveString array value: fourString array value: nineString array value: oneString array value: sevenString array value: sixString array value: tenString array value: threeString array value: two

Comments

What makes std::array better than std::vector is that there is no need for extra code to support a dynamic container like vector. The container array is like the simpler C fixed array, in that it’s fixed and static, but has enough container traits that it can be used in a C++ ranged for loop (lines 15,23, and 29), as show in the example above.

Using std::array in an Embedded Application

I have been writing ESP32-S3 and ESP32-C3 C++ code. I’ve published the following code more than once, but this time, I just want to highlight how I replaced the C++ standard library vector and tuple type with array. Here is where std::array helps in dropping the size of the binary. I checked the size of the generated binary (everything else the same) and discovered that I save a bit of 10K of generated binary, meaning that I saved 10K by switching to array. What’s more the ability to access the elements of the inner array in line 44 makes a lot more sense than the older way of declaring the inner colors a tuple and the convoluted way I accessed tuple members the way I did.

#include <stdio.h>#include <array>#include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "driver/gpio.h"#include "esp_log.h"#include "led_strip.h"#include "sdkconfig.h"using std::array;const array<array<int, 3>, 7> colors {{{32,0,0},  // red{0,32,0},  // green{0,0,32},  // blue{0,32,32}, // cyan{32,0,32}, // magenta{32,16,0}, // yellow{0,0,0}// black}};// Task 1.//static void task_blink_neo_pixel(void * pvParameters) {static led_strip_t *pStrip_a;pStrip_a = led_strip_init(CONFIG_BLINK_LED_RMT_CHANNEL, CONFIG_BLINK_GPIO, 1);pStrip_a->clear(pStrip_a, 50);// Stay in an endless loop. Don't return from this task.//while(true) {for(auto color : colors) {pStrip_a->set_pixel(pStrip_a, 0, color[0], color[1], color[2]);pStrip_a->refresh(pStrip_a, 100);vTaskDelay(500 / portTICK_PERIOD_MS);// Set NeoPixel LED dark by clearing all its individual LEDs.pStrip_a->clear(pStrip_a, 50);vTaskDelay(500 / portTICK_PERIOD_MS);}}}// Task 2.//static void task_blink_led(void * pvParameters) {gpio_reset_pin(GPIO_NUM_46);// Set the GPIO as a push/pull output//gpio_set_direction(GPIO_NUM_46, GPIO_MODE_OUTPUT);// Stay in an endless loop. Don't return from this task.//while (true) {gpio_set_level(GPIO_NUM_46, true);   // LED onvTaskDelay(100 / portTICK_PERIOD_MS);gpio_set_level(GPIO_NUM_46, false);  // LED offvTaskDelay(100 / portTICK_PERIOD_MS);gpio_set_level(GPIO_NUM_46, true);   // LED onvTaskDelay(100 / portTICK_PERIOD_MS);gpio_set_level(GPIO_NUM_46, false);  // LED offvTaskDelay(2700 / portTICK_PERIOD_MS);}}extern "C" void app_main(void) {static const char *TAG = "DUAL_BLINK";int core = xPortGetCoreID();ESP_LOGI(TAG, "app_main running on core %i", core);ESP_LOGI(TAG, "CONFIG_BLINK_GPIO %i", CONFIG_BLINK_GPIO);// Create task 1.//TaskHandle_t xHandle1 = NULL;static uint8_t ucParameterToPass1 = 1;xTaskCreate(task_blink_neo_pixel,"BlinkNeoPixel",// human readable task name.2048,   // stack size in bytes.&ucParameterToPass1,tskIDLE_PRIORITY,&xHandle1);configASSERT(xHandle1);// Create task 2.//TaskHandle_t xHandle2 = NULL;static uint8_t ucParameterToPass2 = 1;xTaskCreate(task_blink_led,"BlinkLED", // human-readable task name.2048,   // stack size in bytes.&ucParameterToPass2,tskIDLE_PRIORITY,&xHandle2);configASSERT(xHandle2);// Stay in an endless loop. Don't return from this task.//while (true) {vTaskDelay(1000 / portTICK_PERIOD_MS);}}