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



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

751   8  

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++" будет таким

#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:: массив, который моделирует массив постоянного размера (против вектора, который может расти). Существует также 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 или цикл для динамического выделения необработанной памяти, в зависимости от того, как переменная я ожидаю, что эта область кода будет в будущем.

Comments

    Ничего не найдено.