Как инициализировать память с помощью оператора new в C++?

Я только начинаю в C++ и я хочу, чтобы забрать некоторые хорошие привычки. Если я только что выделил массив типа int с new оператор, как я могу инициализировать их все до 0, не прокручивая их все сам? Должен ли я просто использовать memset? Есть ли способ" C++ " сделать это?

8 ответов


Это удивительно малоизвестная функция C++ (о чем свидетельствует тот факт, что никто еще не дал этого ответа), но на самом деле у нее есть специальный синтаксис для инициализации массива по умолчанию (ну, технически это называется "value-initialize" в стандарте):

new int[10]();

обратите внимание, что вы должны используйте пустые скобки - вы не можете, например, использовать (0) или любое другое выражение (поэтому это полезно только для инициализации по умолчанию).

это явно разрешено ISO C++03 5.3.4[expr.new] / 15, в котором говорится:

новое-выражение, которое создает объект типа T инициализирует этот объект следующим образом:

...

  • если новый инициализатор имеет форму (), элемент инициализируется значением (8.5);

и не ограничивает типы, для которых это разрешено, тогда как (expression-list) форма явно ограничен далее правила в том же разделе такие, что он не разрешает типы массивов.


предполагая, что вы действительно хотите массив, а не std:: vector, "c++ way" будет следующим

#include <algorithm> 

int* array = new int[n]; // Assuming "n" is a pre-existing variable

std::fill_n(array, n, 0); 

но имейте в виду, что под капотом это все еще просто цикл, который присваивает каждому элементу 0 (на самом деле нет другого способа сделать это, исключая специальную архитектуру с поддержкой аппаратного уровня).


существует несколько методов для выделения массива внутреннего типа, и все эти методы являются правильными, хотя какой из них выбрать, зависит...

ручная инициализация всех элементов в цикле

int* p = new int[10];
for (int i = 0; i < 10; i++)
{
    p[i] = 0;
}

используя std::memset С <algorithm>

int* p = new int[10];
std::fill_n(p, 10, 0);

используя std::vector контейнер

std::vector<int> v(10); // elements zero'ed

если C++0x доступно, используя список инициализатора особенности

int a[] = { 1, 2, 3 }; // 3-element static size array
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime

если выделяемая Вами память является классом с конструктором, который делает что-то полезное, оператор new вызовет этот конструктор и оставит ваш объект инициализированным.

но если вы выделяете POD или что-то, что не имеет конструктора, который инициализирует состояние объекта, тогда вы не можете выделить память и инициализировать эту память с помощью оператора new в одной операции. Однако, у вас есть несколько вариантов:

1) Используйте переменную стека вместо. Вы можете выделить и по умолчанию-инициализировать в один шаг, вот так:

int vals[100] = {0};  // first element is a matter of style

2) использовать memset(). Обратите внимание, что если объект, который вы выделяете, не является POD, memsetting это плохая идея. Один конкретный пример - если вы memset класс, который имеет виртуальные функции, вы сдуете vtable и оставите свой объект в непригодном состоянии.

3) многие операционные системы имеют вызовы, которые делают то, что вы хотите-выделяют в куче и инициализируют данные к чему-то. Примером Windows может быть VirtualAlloc()

4) это, как правило, лучший вариант. Избегайте необходимости управлять памятью самостоятельно. Вы можете использовать контейнеры STL, чтобы сделать почти все, что вы сделали бы с необработанной памятью, включая выделение и инициализацию всего одним махом:

std::vector<int> myInts(100, 0);  // creates a vector of 100 ints, all set to zero

Да есть такое:

std::vector<int> vec(SIZE, 0);

используйте вектор вместо динамически выделенного массива. Преимущества включают в себя не нужно беспокоиться о явном удалении массива (он удаляется, когда вектор выходит за рамки), а также, что память автоматически удаляется, даже если есть исключение.

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

теперь с C++11 есть также std:: array, который моделирует массив постоянного размера (vs vector, который может расти). Существует также std:: unique_ptr, который управляет динамически выделенным массивом (который может быть объединен с инициализацией, как ответили в других ответах на этот вопрос). Любой из них является более C++ способом, чем ручная обработка указателя на массив, ПО МОЕМУ.


std::fill Это один из способов. Принимает два итератора и значение для заполнения области. Это, или цикл for, будет (я полагаю) более C++ способом.

для установки массива примитивных целочисленных типов в 0 конкретно,memset это нормально, хотя это может поднять брови. Рассмотрим также calloc, хотя это немного неудобно использовать С C++ из-за приведения.

со своей стороны, я в значительной степени всегда использую цикл.

(Я не люблю критиковать людей намерения, но это правда, что std::vector - это, при прочих равных условиях, предпочтительнее использовать new[].)


вы всегда можете использовать функцию memset:

int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));

обычно для динамических списков элементов используется std::vector.

обычно я использую memset или цикл для динамического выделения необработанной памяти, в зависимости от того, насколько переменной я ожидаю, что эта область кода будет в будущем.