Объявление массивов в С++
Я новичок в С++ и в настоящее время изучаю его с помощью книги. Эта книга, похоже, говорит, что в зависимости от того, как вы ее объявляете, существует несколько типов массивов. Я думаю, что разница между динамическими массивами и статическими массивами ясна для меня. Но я не понимаю разницы между классом STL std::array
и статическим массивом.
Переменная STL std::array
объявляется как:
std::array < int, arraySize > array1;
В то время как переменная статического массива объявляется как:
int array1[arraySize];
Есть ли принципиальная разница между этими двумя? Или это просто синтаксис, и оба они в основном одинаковы?
Ответы
Ответ 1
A std::array<>
- это просто световая оболочка вокруг массива C-стиля, с некоторыми дополнительными приятными функциями члена интерфейса (например, begin
, end
и т.д.) и typedef
s, грубо определяемый как
template<typename T, size_t N>
class array
{
public:
T _arr[N];
T& operator[](size_t);
const T& operator[](size_t) const;
// other member functions and typedefs
}
Одно фундаментальное отличие состоит в том, что первое может быть передано по значению, тогда как для последнего вы передаете только указатель на его первый элемент или вы можете передать его по ссылке, но вы не можете скопировать его в функцию (кроме как через std::copy
или вручную).
Общей ошибкой является предположить, что каждый раз, когда вы передаете массив C-стиля функции, вы теряете свой размер из-за разложения массива на указатель. Это не всегда верно. Если вы передадите его по ссылке, вы можете восстановить его размер, так как в этом случае нет распада:
#include <iostream>
template<typename T, size_t N>
void f(T (&arr)[N]) // the type of arr is T(&)[N], not T*
{
std::cout << "I'm an array of size " << N;
}
int main()
{
int arr[10];
f(arr); // outputs its size, there is no decay happening
}
Live on Coliru
Ответ 2
Основное различие между этими двумя важными.
Помимо хороших методов, которые STL дает вам при передаче std::array
функции, нет распада. Значение, когда вы получаете std::array
в функции, оно по-прежнему является std::array
, но когда вы передаете массив int[]
в функцию, он эффективно распадается на указатель int*
, а размер массива равен потеряны.
Это различие является основным. Как только вы потеряете размер массива, код теперь подвержен множеству ошибок, так как вы должны отслеживать размер массива вручную. sizeof()
возвращает размер типа указателя вместо количества элементов в массиве. Это заставляет вас вручную отслеживать размер массива с помощью таких интерфейсов, как process(int *array, int size)
. Это одобренное решение, но склонное к ошибкам.
См. рекомендации Bjarne Stroustroup:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rp-run-time
Этого можно избежать с помощью лучшего типа данных, для которого std::array
предназначен для многих других классов STL.
В качестве побочного примечания, если нет веских причин использовать массив фиксированного размера, std::vector
может быть лучшим выбором в качестве структуры непрерывных данных памяти.
Ответ 3
std::array
и массивы C-стиля аналогичны:
- Они оба сохраняют непрерывную последовательность объектов
- Они оба являются совокупными типами и поэтому могут быть инициализированы с помощью агрегатной инициализации
- Их размер известен во время компиляции
- Они не используют распределение динамической памяти
Важным преимуществом std::array
является то, что он может быть передан по значению и не неявно распадается на указатель, как это делает массив в стиле C.
Ответ 4
В обоих случаях массив создается в стеке.
Однако шаблон шаблона STL std::array
предлагает некоторые преимущества перед синтаксисом "сырой" синтаксиса C-типа вашего второго случая:
int array1[arraySize];
Например, при std::array
у вас есть типичный интерфейс STL с такими методами, как size
(который вы можете использовать для запроса количества элементов массива), front
, back
, at
и т.д.
Вы можете найти более подробную информацию здесь.
Ответ 5
Есть ли принципиальная разница между этими двумя? или это просто синтаксис, и оба они в основном одинаковы?
Существует ряд отличий для исходного массива c-style (встроенный массив) по сравнению с std::array
.
Как видно из справочной документации, имеется ряд доступных операций, которые не имеют сырой массив:
Например: доступ к элементу
at()
front()
back()
data()
Основной тип данных std::array
по-прежнему является сырым массивом, но украшен "синтаксическим сахаром" (если это вас беспокоит).
Ответ 6
Ключевыми отличиями std::array<>
и массива C-стиля являются то, что первое является классом, который обтекает последний. Класс имеет методы begin()
и end()
, которые позволяют легко переносить объекты std::array
в качестве параметров для алгоритмов STL, ожидающих итераторов (обратите внимание, что массивы C-стиля могут также использоваться с помощью методов non member std::begin
/std::end
). Первый указывает на начало массива, а второй указывает на один элемент за его пределами. Вы видите этот шаблон с другими контейнерами STL, такими как std::vector
, std::map
, std::set
и т.д.
Что также приятно в STL std::array
, так это то, что у него есть метод size()
, который позволяет получить количество элементов. Чтобы получить количество элементов массива C-стиля, вам нужно написать sizeof(cArray)/sizeof(cArray[0])
, так что stlArray.size()
выглядит намного читабельнее?
Вы можете получить полную ссылку здесь:
http://en.cppreference.com/w/cpp/container/array
Ответ 7
Обычно вам следует предпочесть std::array<T, size> array1;
над T array2[size];
, поскольку базовая структура идентична.
Основная причина заключается в том, что std::array
всегда знает свой размер. Вы можете вызвать метод size(), чтобы получить размер. Если вы используете массив C-стиля (т.е. То, что вы называете "встроенным массивом" ), вам всегда приходится передавать размер вокруг функций, которые работают с этим массивом. Если вы каким-то образом ошибетесь, вы можете вызвать переполнение буфера, и функция пытается читать/записывать в память, которая больше не принадлежит массиву. Это не может произойти с std::array
, потому что размер всегда ясен.
Ответ 8
IMO,
-
Плюсы: эффективен, поскольку он не использует больше памяти, чем встроенные фиксированные массивы.
-
Минусы: std::array
по встроенному фиксированному массиву является немного более неудобным синтаксисом и что вы должны явно указать длину массива (компилятор не рассчитает его для вас из инициализатора).