2016-11-23 2 views
15

Я новичок в C++ и в настоящее время изучаю его с помощью книги. Эта книга, похоже, говорит, что в зависимости от того, как вы ее объявляете, существует несколько типов массивов. Я думаю, что разница между динамическими массивами и статическими массивами ясна для меня. Но я не понимаю разницы между классом STL std::array и статическим массивом.Объявление массивов в C++

STL std::array переменная объявлена ​​как:

std::array < int, arraySize > array1; 

В то время как статическая переменная массив объявлен как:

int array1[arraySize]; 

Есть ли принципиальная разница между этими двумя? Или это просто синтаксис, и они в основном одинаковы?

+0

Нет разницы, только вопрос синтаксиса и я считаю, что было доступно только C++ 11 и выше, однако заметить, что декларация STL дает вам большой набор инструментов функций и итераторы, которые можно использовать в массиве, как и другие один из них, как правило, должен был бы встроить в себя функции, чтобы выполнить тривиальные вещи. Проверьте: http://en.cppreference.com/w/cpp/container/array –

+0

Возможный дубликат [std :: array vs array performance] (http://stackoverflow.com/questions/30263303/stdarray-vs-array-performance) – coincoin

+6

Будет большая разница, если вы начнете передавать 'std :: array <>' функции в отличие от встроенных массивов. «Std :: array» знает свой собственный размер, встроенный массив не работает, когда он распадается на указатель. – PaulMcKenzie

ответ

22

std::array<> это просто света обертка вокруг массива С-типа, с некоторыми дополнительными хорошими функциями членов интерфейса (например, begin, end и т.д.) и typedef с, примерно определяются как

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

+0

Вы можете передать массив C-стиля по ссылке или указателем на сам массив. – SergeyA

+1

@SergeyA Я думаю, что я был немного неясен, отредактирован. Дело в том, что вы определенно не можете передать его по значению. – vsoftco

5

В обоих случаях массив создается на стеке.

Однако шаблон std::array класса в STL предлагает некоторые преимущества по сравнению с «сырым» C-подобный синтаксисом массива Вашего второго случая:

int array1[arraySize]; 

Например, с std::array у вас есть типичный STL интерфейс, с помощью методов, как size (которые вы можете использовать для запроса количества элементов в массиве), front, back, at и т.д.

Вы можете найти более подробную информацию here.

+3

"* В обоих случаях массив создается в стеке *" - если только он не является членом структуры/класса, выделенной в куче. –

6
массивов

std::array и С-типа подобны:

  • Они оба хранит непрерывную последовательность объектов
  • Они оба агрегатный тип и, следовательно, могут быть инициализированы с помощью aggregate initialization
  • Их размер известен в время
  • компилировать Они не используют динамическое выделение памяти

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

1

Обычно вы должны предпочесть std::array<T, size> array1; над T array2[size];, althoug базовая структура идентична.

Основная причина в том, что std::array всегда знает свои размеры. Вы можете вызвать его метод size(), чтобы получить размер. Если вы используете массив C-стиля (т. Е. То, что вы называете «встроенным массивом»), вам всегда приходится передавать размер вокруг функций, которые работают с этим массивом. Если вы каким-то образом ошибетесь, вы можете вызвать переполнение буфера, и функция пытается читать/записывать в память, которая больше не принадлежит массиву. Это не может произойти с std::array, так как размер всегда ясен.

+0

В C++ нет необходимости всегда передавать размер, даже для массивов в стиле C. Вы можете передать массив по ссылке через функцию шаблона и восстановить его размер. – vsoftco

2

Ключевыми отличиями std::array<> и массива C-стиля являются то, что первый класс относится к последнему. Класс имеет методы begin() и end(), которые позволяют легко передавать объекты std::array в качестве параметров для алгоритмов STL, ожидающих итераторов (обратите внимание, что массивы C-стиля также могут быть использованы с помощью методов, не связанных с std::begin/). Первый указывает на начало массива, а второй указывает на один элемент за его пределами. Вы видите эту модель с другими контейнерами STL, такие как std::vector, std::map, std::set и т.д.

Что также хорошо о СТЛ std::array является то, что он имеет size() метод, который позволяет получить количество элементов. Чтобы получить количество элементов массива C-стиля, вам нужно будет написать sizeof(cArray)/sizeof(cArray[0]), так что не stlArray.size() выглядит намного читабельнее?

Вы можете получить полную ссылку здесь:

http://en.cppreference.com/w/cpp/container/array

+0

Не-член 'begin' и' end' отлично работают с массивами C-стиля. С помощью этих других улучшений (переход на не-членные шаблоны) вы ничего не говорите правильно: массивы могут обрабатываться с помощью алгоритмов с требованием обертки для этого. В массивах всегда есть итераторы; делая их точно так же, как указатели, был основополагающим принципом. –

+1

Добавлена ​​ваша записка о том, как начинать/заканчивать нечлен. –

+2

«Чтобы получить количество элементов массива C-стиля, вам придется писать» yuck, и нет, вы этого не делаете. Шаблон, показанный в ответе vsoftco, иллюстрирует, как N выводится как аргумент шаблона. Или просто используйте 'end (a) -begin (a)', но зачем вам это нужно, когда вы должны * пропускать итераторы или «диапазон». C массив ** является ** хорошим диапазоном: оболочка массива не нужна по любой из этих причин. –

3

Есть ли принципиальная разница между этими двумя? или это просто синтаксис, и оба они в основном одинаковы?

Там есть ряд отличий для исходного массива с-стиле (встроенный массив) по сравнению с std::array.

Как вы можете видеть из справочной документации есть ряд операций, доступных, которые не с сырым массивом:

Э.Г.: Элемент доступа

at() 
front() 
back() 
data() 

Основной тип данных std::array еще сырой массив, но украшенный «синтаксический сахар» (если это должно быть ваше беспокойство).

8

Главное отличие этих двух является важным.

Помимо приятных методов, которые STL дает вам при передаче функции std::array, нет распада. Значение, когда вы получаете std::array в функции, оно по-прежнему является std::array, но когда вы передаете массив int[] функции, он эффективно распадается на указатель int* и размер массива будет потерян.

Эта разница важна. Как только вы потеряете размер массива, код теперь подвержен множеству ошибок, так как вы должны отслеживать размер массива вручную. sizeof() возвращает размер типа указателя вместо количества элементов в массиве. Это заставляет вас вручную отслеживать размер массива с помощью таких интерфейсов, как process(int *array, int size). Это одобренное решение, но склонное к ошибкам.

Смотрите принципы Бьярне Stroustroup:

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rp-run-time

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

В качестве побочного примечания, если нет веской причины использовать массив фиксированного размера, std::vector может быть лучшим выбором в качестве непрерывной структуры данных памяти.

1

IMO,

  • Плюсы: Это эффективно, в том, что он не использует больше памяти, чем встроенный в фиксированных массивов.

  • Против: std::array по встроенному фиксированному массиву является немного более неудобным синтаксисом и что вы должны явно указать длину массива (компилятор не рассчитает его для вас из инициализатора).

Смежные вопросы