Будут ли экземпляры шаблона std :: array занимать больше памяти кода?

У меня есть микроконтроллер, у которого нет MMU, но мы используем C и C ++.

Мы избегаем всего динамического использования памяти (то есть нет new SomeClass() или же malloc()) и большая часть стандартной библиотеки.

Полу-вопрос 0:

Из того, что я понимаю std::array не использует динамическую память, поэтому ее использование должно быть в порядке (только в стеке). Смотря на std::array Исходный код выглядит хорошо, так как создает массив в стиле c, а затем оборачивает функциональность вокруг этого массива.

Чип, который мы используем, имеет 1 МБ флэш-памяти для хранения кода.

Вопрос 1:

Я обеспокоен тем, что использование шаблонов в std::array приведет к тому, что двоичный файл будет больше, что может привести к превышению предела памяти кода в 1 МБ.

Я думаю, что если вы создадите экземпляр std::array< int, 5 >, то все вызовы функций на что std::array будет занимать определенный объем памяти кода, скажем, X байт памяти.

Если вы создаете другой экземпляр std::array< SomeObject, 5 >затем вызовите функции к этому std::arrayБудет ли каждая из этих функций теперь дублироваться в двоичном коде, занимая при этом больше памяти кода? X байт памяти + Y байт памяти.

Если да, думаете ли вы, что объем кода, сгенерированный с учетом ограниченного объема памяти кода, будет проблемой?

Вопрос 2:

В приведенном выше примере, если вы создали второй std::array< int, 10 > Например, будут ли вызовы функций дублировать вызовы функций в сгенерированном коде? Хотя оба экземпляра одного типа, int?

1

Решение

std::array считается абстракцией с нулевой стоимостью, что означает, что она должна быть довольно оптимизируемой компилятором.

Как и в случае любой абстракции с нулевой стоимостью, она может вызывать небольшую пенальтию времени компиляции, и если требуемые оптимизации действительно нулевые затраты не поддерживаются, то это может привести к небольшому размеру или штрафу времени выполнения.

Тем не менее, обратите внимание, что компилятор может добавлять отступы в конце структуры. поскольку std::array это структура, вы должны проверить, как ваша платформа обрабатывает std::arrayНо я очень сомневаюсь, что это так для вас.

Возьми этот массив и std::array дело:

#include <numeric>
#include <iterator>

template<std::size_t n>
int stuff(const int(&arr)[n]) {
return std::accumulate(std::begin(arr), std::end(arr), 0);
}

int main() {
int arr[] = {1, 2, 3, 4, 5, 6};
return stuff(arr);
}

#include <numeric>
#include <iterator>
#include <array>

template<std::size_t n>
int stuff(const std::array<int, n>& arr) {
return std::accumulate(std::begin(arr), std::end(arr), 0);
}

int main() {
std::array arr = {1, 2, 3, 4, 5, 6};
return stuff(arr);
}

Clang поддерживает это дело очень хорошо. все случаи с std::array или необработанные массивы обрабатываются одинаково:

-O2 / -O3 и массив и std::array с лязгом:

main: # @main
mov eax, 21
ret

Однако у GCC, похоже, есть проблемы с его оптимизацией, поскольку std::array и случай необработанного массива:

-O3 с GCC для массива и std::array:

main:
movdqa xmm0, XMMWORD PTR .LC0[rip]
movaps XMMWORD PTR [rsp-40], xmm0
mov edx, DWORD PTR [rsp-32]
mov eax, DWORD PTR [rsp-28]
lea eax, [rdx+14+rax]
ret
.LC0:
.long 1
.long 2
.long 3
.long 4

Тогда, кажется, лучше оптимизировать с -O2 в случае необработанного массива и сбой с std::array:

-O2 НКУ std::array:

main:
movabs rax, 8589934593
lea rdx, [rsp-40]
mov ecx, 1
mov QWORD PTR [rsp-40], rax
movabs rax, 17179869187
mov QWORD PTR [rsp-32], rax
movabs rax, 25769803781
lea rsi, [rdx+24]
mov QWORD PTR [rsp-24], rax
xor eax, eax
jmp .L3
.L5:
mov ecx, DWORD PTR [rdx]
.L3:
add rdx, 4
add eax, ecx
cmp rdx, rsi
jne .L5
rep ret

-O2 Необработанный массив GCC:

main:
mov eax, 21
ret

Похоже, что ошибка GCC не удалось оптимизировать -O3 но преуспеть с -O2 исправлено в самой последней сборке.

Вот проводник компилятора со всеми O2 и O3


С учетом всех этих случаев вы можете увидеть общую картину: никакой информации о std::array выводится в двоичном виде. Там нет конструкторов, нет operator[], даже не итераторы, ни алгоритмы. Все встроено. Компилятор хорош во вложении простых функций. std::array функции-члены обычно очень очень просты.

Если вы создаете другой экземпляр std :: array< SomeObject, 5>, затем вызывает функции для этого std :: array, будет ли каждая из этих функций теперь дублироваться в двоичном файле, занимая при этом больше флэш-памяти? X байт памяти + Y байт памяти.

Итак, вы изменили тип данных, который содержит ваш массив. Если вы вручную добавите перегрузку всех своих функций для обработки этого дополнительного случая, то да, все эти новые функции могут занять некоторое пространство. Если ваша функция мала, у них есть большой шанс быть встроенными и занимать меньше места. Как вы можете видеть из приведенного выше примера, встраивание и постоянное сворачивание могут значительно уменьшить ваш двоичный размер.

В приведенном выше примере, если вы создали второй экземпляр std :: array, будут ли вызовы функций дублировать вызовы функций во флэш-памяти? Хотя оба экземпляра одного типа, int?

Опять это зависит. Если у вас есть много функций, настроенных по размеру массива, оба std::array а необработанные массивы могут «создавать» разные функции. Но опять же, если они вписаны, нет дубликата, о котором нужно беспокоиться.

Оба будут необработанным массивом и std::arrayВы можете передать указатель на начало массива и передать размер. Если вы найдете это более подходящим для вашего случая, то используйте его, но все еще необработанный массив и std::array могу сделать это. Для необработанного массива он неявно затухает до указателя и std::array, вы должны использовать arr.data() чтобы получить указатель.

5

Другие решения

Неинициализированный массив не использует flash, за исключением кода, связанного с его использованием.

-1