#c #vector #heap-memory
#c #вектор #куча-память
Вопрос:
При изучении c я обычно (очень часто) сталкиваюсь со следующим советом: «Избегайте динамического выделения памяти, насколько можете; вместо этого используйте std:: vectors, поскольку они справляются с этим за вас».
Итак, мой вопрос: когда я должен использовать динамическое выделение памяти? Все упражнения, которые я выполнил (я всего лишь новичок), намного проще в использовании std::vector
; тем не менее, мой лектор заставляет нас использовать динамическую память для простых классов (таких как матрицы, геометрические векторы и т.д.) И delete[]
в деструкторе.
Единственное преимущество, которое я нашел до сих пор для new;delete[];
(или, по крайней мере, то, что я говорю себе, чтобы почувствовать, что стоит использовать динамическую память), — это использование копирования перемещения и назначения перемещения.
Комментарии:
1. «Единственное преимущество, которое я нашел до сих пор …» Вы говорите о
std::vector
илиnew
/delete
?2. std::vector выполняет динамическое выделение памяти. Дело в том, что вы не должны делать это напрямую (или, по крайней мере, делать это в оболочке), а не не делать этого вообще
3. Вы должны использовать динамическое выделение памяти всякий раз, когда вам говорит ваш лектор. Предположительно, цель состоит в том, чтобы научиться управлять динамическим выделением памяти или, возможно, узнать, почему вы не должны делать это самостоятельно.
4. Единственное преимущество, которое я пока нашел для new;delete[]; (или, по крайней мере, то, что я говорю себе, чтобы почувствовать, что стоит использовать динамическую память), — это использование move copy и move assignment. Не хочется взрывать ваш пузырь, но с
new
/delete
вам придется писать свои собственные конструкторы, что является работой. С помощьюstd::vector
вам не нужно ничего писать. Вы получаете конструкторы копирования / перемещения, операторы присваивания копирования / перемещения и деструктор, предоставленные вам компилятором, что требует гораздо меньше работы.5. @James Но это изменит, какие правильные конструкторы вы получите. Значения по умолчанию неприемлемы, если вы используете
new
/delete
Ответ №1:
std::vector
также выполняет динамическое выделение памяти за кулисами (с помощью new
оператора). Для std::vector
, как вы можете видеть здесь, также определены назначение копирования и перемещения, поэтому, если вы делаете это вручную, скорость не увеличивается.
Вероятно, ваш вопрос относится к тому, когда вам следует вручную выделять память (явно используя new
и delete
), в отличие от того, чтобы полагаться на другой класс (например, vector), который сделает это за вас.
Ответ «Современного C » на этот вопрос заключается в том, чтобы никогда не выполнять управление памятью вручную. Если std::vector
выполняет эту работу, то используйте это вместо. Если вам нужно выделить один элемент, то используйте std::unique_ptr
.
Комментарии:
1. Не совсем, моя придирка заключается в том, что для выделения и инициализации памяти
std::vector
используется распределитель . Это важное различие, поскольку распределители могут быть настроены для каждого экземпляраoperator new
в этом случае они были бы глобальными.2.«никогда не выполнять управление памятью вручную» — это еще более сильное утверждение, чем «избегайте этого, насколько можете». Вы предполагаете, что это возможно никогда не понадобится
new;delete[]
?3. @Mgetz
std::vector<T>
используетstd::allocator<T>
то, что используетoperator new
, что является хорошим поведением по умолчанию.4. @Mgetz Для любого использования по умолчанию он вызовет
new
: timsong-cpp.github.io/cppwp/… Комментарий к ответу может быть не на 100% точным, но он будет охватывать большинство случаев.5. @NathanOliver @caleth вы оба полностью пропустили то, к чему я клонил. Тот факт, что он будет использовать
operator new
по умолчанию, не имеет отношения к педантизму. Дело в том, чтоstd::vector
это не жестко привязано кoperator new
. Я не уверен, что мне не удается сообщить здесь. Это будет мой последний пост, поскольку я становлюсь довольно расстроенным тем, насколько неактуальным это стало. Мой пост был придиркой, я не считаю сообщение респондента принципиально ошибочным по причинам, которые вы указали. Я просто предоставлял дополнительную информацию.
Ответ №2:
Бывают ситуации, когда вам может понадобиться реализовать пользовательский контейнер (поскольку ни std::vector
один из других стандартных библиотечных контейнеров не подходит для ваших целей), и в таких случаях может иметь смысл выполнять управление памятью вручную.
Однако, если вы не предоставляете низкоуровневые компоненты ядра в какой-либо базе кода промышленного класса и не преследуете очень конкретные цели, ручное управление памятью, вероятно, здесь также не требуется.
Я согласен со строгими правилами вашего лектора, поскольку важно понимать, что происходит за кулисами. Вам редко, если вообще когда-либо, придется использовать ручное управление памятью, но это помогает понять, как std::unique_ptr
/ std::vector
(должны) это сделать для вас, чтобы понять, почему C был построен таким, какой он есть. Обучение C способом, который полезен в реальном мире, в конечном итоге позволит / заставит вас использовать стандартные библиотечные контейнеры, хотя, потому что (как вы правильно заметили), по сути, нет причин когда-либо писать delete
.
Ответ №3:
Лектор, скорее всего, заставляет вас, чтобы вы получили представление о том, как все работает под капотом. Класс std::vector, как вы упомянули, обрабатывает все динамическое управление памятью за вас, так что вам не нужно писать весь код, чтобы справиться с этим самостоятельно. Легко, особенно новичку, ошибиться при обработке динамической памяти и создать утечку / забыть что-либо освободить.
Однако вектор не является решением для каждой проблемы, и вы можете найти случаи, когда он не соответствует всем вашим критериям — и в этих случаях было бы лучше реализовать вашу собственную структуру данных.
Комментарии:
1. «лектор, скорее всего, заставляет вас, чтобы вы получили представление о том, как все работает под капотом» Само по себе это неплохо, но большую часть времени они даже не потрудились рассказать студентам о правиле трех. D:
2. Не могли бы вы привести базовый пример, когда вектор не соответствует всем моим критериям, и было бы лучше напрямую динамически выделять память?
3. @DanielDuque Я здесь указывал на использование карт, деревьев или других структур, которые могут быть более эффективными для определенных операций. Для динамического массива я бы всегда использовал вектор вместо ручного динамического выделения памяти
4. @DanielDuque случаи, требующие чрезвычайно строгих стандартов выравнивания для чрезвычайно высокопроизводительного кода.
5. «и в этих случаях могло бы быть лучше использовать другую структуру данных, в этом случае посмотрите на другие
std
контейнеры,boost
containers, и только если ни один из них не соответствует вашим потребностям, реализуйте свою собственную структуру данных»