2014-12-16 2 views
2

Что (если что-либо) можно сделать более эффективно с помощью массива, а не контейнера?Почему я должен использовать простые массивы, а не классы контейнеров?

Недавно я узнал о стандартных классах контейнеров C++. Они имеют явные преимущества и решают общие проблемы с массивами C-стиля. В FAQ сек список на «почему массивы зла» можно резюмировать свободно, как это:

1. subscripts are not checked 
2. often it is required to allocate memory from the heap 
3. not easy to insert elements in the middle 
4. always passed as reference 

Я думаю, есть много случаев, где можно жить с этими недостатками. Тем не менее, я немного озадачен вопросом, что это может быть сделано более эффективно/проще с массивами, а не с контейнерами? Или на самом деле ничего подобного, и я действительно не должен заботиться о массивах?

+0

Пожалуйста, просмотрите их страницу на [что означает «зло»] (http://www.parashift.com/c++-faq/defn-evil.html). TL, DR не воспринимают это слишком серьезно. (Было бы нечестно предположить, что в FAQ часто говорится, что вы никогда не используете массивы снова.) –

+0

Учитывая C++ 11, существует 'std :: array', который AFAIK полностью заменяет массивы C-стиля. Они необходимы для реализации 'std :: array' и не могут быть удалены, поскольку это приведет к серьезному нарушению совместимости, но если вы пишете C++ 11, на самом деле нет причин использовать массивы. Конечно, ЧаВо, скорее всего, предшествует C++ 11, поэтому это хороший вопрос для C++ 98. – delnan

+0

@remyabel да, вы правы, я отредактирую. На самом деле я подумывал о том, чтобы не упоминать о ссылках на faq (и «злую» -добавку), поскольку ее неправильно понимают и критикуют уже достаточно часто. – user463035818

ответ

6

«Тем не менее, я немного озадачен вопросом, что же можно сделать более эффективным/проще с массивами, а не с контейнерами?»

Ну, если вы имеете в виду массивы с стиле с текущей с стандарта ++, не осталось ничего о недостатках классических стандартных C++ классов контейнера (например, например, std::vector) ИМХО. У них есть зависимость от выделенной памяти (с new()), и это вполне может быть ограничением для вашей текущей (OS/bare metal) среды, поскольку она недоступна из коробки.


Текущий стандарт обеспечивает std::array, который работает без динамических потребностей распределения памяти, но выполняет все претензии:

"1. Индексы не проверяются"

std::array проверяет индекс

"2. часто требуется выделить память из кучи»

Это выбор клиента, где он на самом деле выделяется std::array. std::vector хватает в любом случае для этого.

«3. Не легко вставлять элементы в середине»

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

«4. всегда передается в качестве ссылки»

std::array поддерживает передачу по ссылке хорошо, и намного лучше, чем может (не может) быть достигнуто с помощью c-style массивов.


Хотя могут быть специализированные случаи, например. многопользовательские пулы экземпляров объектов или экземпляры объектов flyweight, вы можете решить с помощью оператора placement new(). Реализации для таких решений обычно связаны с тем, что вы собираетесь работать с необработанными массивами c-style.

+1

Фактически существует _is_ a nit, где встроенные массивы имеют преимущество перед всеми альтернативами: вы можете создать встроенный массив в стеке с соответствием размерам его список инициализаторов. Не большой, но на самом деле важный ... –

+0

Возможно, это потому, что я устал, но едва могу сделать головы или хвосты этого первого абзаца. Не могли бы вы перефразировать его? –

+0

Этот ответ лежит в основе проблемы. Самая большая разница с векторами - их зависимость от кучи. Для случаев, когда вы знаете пропускную способность во время компиляции, но все же хотите, чтобы большинство функций/защиты векторного std :: массива - путь. ** Если ** вы не взаимодействуете с массивами c-style, и вы не хотите копировать данные. В этом случае вы только выбор будет reinterpret_cast, что просто не очень хорошая идея. http://stackoverflow.com/questions/11205186/treat-c-cstyle-array-as-stdarray – cmaynard

1

Или нет на самом деле ничего подобного, и я действительно не должен заботиться о массивах?

Учитывайте, что C++ датируется 1983 годом, и с тех пор он видел ряд больших изменений. Классы контейнеров, которые доступны сейчас, были , разработанные, чтобы избежать ловушек, которые вы указали, поэтому неудивительно, что они лучше в этом отношении. Однако есть одна вещь, которую вы можете сделать с массивами C-стиля, которые вы не можете использовать с современными классами контейнеров: вы можете скомпилировать свой код с очень старыми компиляторами. Если у вас есть насущная необходимость поддерживать совместимость с компиляторами с середины 1980-х годов, вы должны придерживаться массивов в стиле C. В противном случае используйте более новый, лучший подход.

3

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

+0

Существует также противоположный аргумент, что векторы имеют почти ничего лишнего над массивами и что векторы всегда должны быть предпочтительнее. –

+3

Правда, но C++ 11 также включает 'std :: array', который выделяется в стеке, как простые массивы. –

+2

@remyabel Я просто привел пример, где они * делают * имеют накладные расходы над массивом. Если эти условия не применяются, не стесняйтесь выбирать то, что вы хотите. –

1

c-stlye массивы имеют несколько преимуществ перед контейнерами stl (в частности, std::array). Конечно, то же самое верно и наоборот.

Во-первых, с массивами c-style у вас есть контроль над макетом памяти, что чрезвычайно полезно при интерпретации сетевых пакетов или любых подобных источников данных. Это позволяет отнести блок памяти к структуре, сохраняя операции копирования/присваивания, что необходимо в некоторых приложениях с высокой чувствительностью к производительности.

Другая причина - простота - в случае, когда вам не нужны какие-либо преимущества, предлагаемые контейнерами std, зачем их использовать?

И есть совместимость - различные реализации stl будут меняться с разными компиляторами. Использование массивов в интерфейсах разделяемых библиотек (so/dll) вместо stl-контейнеров позволяет пользователю писать против общей библиотеки, используя почти любой компилятор. Это явно не относится к контейнерам stl.

Наконец-то есть оптимизации на низком уровне. Бывают ситуации, когда массивы могут быть быстрее, чем их эквивалент stl std::array, хотя эти ситуации несколько редки.

+1

@ πάνταῥεῖ Нет, это не должен был быть комментарий. –

+0

@LightnessRacesinOrbit По крайней мере, в самой первой форме ответ должен был быть одним ... Убрал мой нисходящий поток после редактирования. –

+0

@ πάνταῥεῖ Даже плохой ответ - это ответ! Я устаю от людей, отправляющих ответы на подобные данные в качестве комментариев, поэтому поэтому слишком чувствителен, когда люди доходят до того, как пытаются сделать это! _ Lol –

3

Встроенные массивы - это инструмент низкого уровня с несколько неудобным интерфейсом. Тем не менее, они необходимы для более эффективного использования классов: одна из приятных особенностей C++ заключается в том, что предоставляет многие инструменты низкого уровня для создания эффективных реализаций абстракций более высокого уровня. Для меня основные виды использования встроенных массивов таковы:

  1. механизм для реализации абстракций более высокого уровня, как std::vector<T> или std::array<T, N> (ну, std::vector<...> и семьи на самом деле не использовать встроенные массивы, но дело diretly с необработанной памятью внутри).
  2. Когда мне нужен массив значений, инициализированных с помощью последовательности значений, выделенных в стеке, я бы использовал встроенные массивы (std::array<...> не смог вывести количество аргументов и ничего, используя std::initializer_list<T> для инициализации, не будет иметь исправленный размер).

Даже если std::array<T, N> действительно просто переписывание [некоторые] функциональность встроенных массивов она имеет хорошую особенность, что реализация отладки может утверждать предположения, которые сделаны.

BTW, вы не включаете в список более крупных проблем: если у вас есть массив с переменным размером, вам нужно указать его тип элемента по умолчанию. С C++ 11 конструктор по умолчанию может, по крайней мере, быть по умолчанию (это проблема, если вашему классу нужен другой конструктор), который может избежать инициализации объектов, которые должны быть инициализированы. Тем не менее, различные классы контейнеров занимают много сложности из-за картины.

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