Динамическое выделение памяти против std :: вектор для закрытого члена класса C

#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, и только если ни один из них не соответствует вашим потребностям, реализуйте свою собственную структуру данных»