#новичкам
На самом деле, это очень-очень тонкая обертка над сишными массивами. Вот несколько упрощенная реализация, которая тем не менее полностью передает смысл и необходимые особенности.
template<typename T, size_t N>
struct array
{
T& operator[](size_t index) {
return _data[index];
}
T& front() {
return _data[0];
}
T& back() {
return _data[N-1];
}
T* data() {
return _data;
}
constexpr size_t size() const {
return N;
}
constexpr bool empty() const {
return N == 0;
}
// еще const версии перечисленных методов и некоторые другие методы и алиасы типов
T _data[N];
};
За счет использования шаблоного типа нижележащего массива std::array может работать с любыми встроенными и кастомными типами.
А за счет нетипового шаблонного аргумента N, std::array знает количество элементов, которое в нем находится, еще на этапе компиляции!. И не нужно ничего вычислять! Достаточно вызвать метод size(), который буквально constexpr.
std::array arr{1, 2, 3};
static_assert(arr.size() == 3); // здесь не упадемОбычно удобство абстракций идет вместе с платой за это удобство. Но это не тот случай. За счет того, что все методы std::array буквально занимают одну строчку, компилятору очень удобно инлайнить их код в caller'ов. Это приводит к тому, что низкоуровневый ассемблерный код при работе с C-style массивами и std::array практически всегда идентичен.
std::array не мимикрирует ни под какой другой тип, так как это кастомный класс. Внутри себя он также инкапсулирует все необходимые операторы сравнения. В операциях с ним нет никакой путаницы, потому что они явно определены конкретно для этого класса. Его можно спокойно принимать в функцию по ссылке и по значению, а также указывать в качестве возвращаемого значения. И все это с привычной семантикой.
template<typename T, size_t N>
std::array<T, N> double_elements(std::array<T, N>& array) {
std::array<T, N> result = array;
for (auto& elem: result)
elem = elem * 2;
return result;
}
Если мы создаем массив в локальной области функции(99% случаев), то элементы std::array располагаются непрерывно на стеке. И размер std::array равен размеру C-style массива с одинаковым количеством элементов и их типом.
int c_arr[N];
std::array<int, N> cpp_arr;
sizeof(cpp_arr) == cpp_arr.size() * sizeof(int) ==
sizeof(c_arr) == N * sizeof(int) == std::size(c_arr) * sizeof(int);
Итак. Выходит, что std::array идентичен сишному массиву по внутреннему устройству и произодительности, да еще и решает все проблемы неумелого использования последнего. Идеальный высокоуровневый инструмент!
Так что std::array должен быть первым выбором в случае необходимости создания массива с длиной, известной на этапе компиляции. У PVS-Studio есть прекрасная статья на этот счет.
Fix your flaws. Stay cool.
#STL #cppcore