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

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

163
задан dreamlax 5 February 2010 в 00:06
поделиться

8 ответов

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

new int[10]();

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

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

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

...

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

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

367
ответ дан 23 November 2019 в 21:16
поделиться

Возможно, атрибут вашего экземпляра использует _ _ slots _ _

Например, socket имеет _ _ slots _ _ , поэтому его нельзя выбрать

Необходимо определить, какой атрибут вызывает ошибку, и записать свой собственный _ _ getstate _ _ и _ _ setstate _ _ для игнорирования этого атрибута

-121--1391376-

Да:

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

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

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

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

-121--669723-

Предполагая, что вы действительно хотите массив, а не std:: вектор, "путь C++" будет таким

#include <algorithm> 

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

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

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

25
ответ дан 23 November 2019 в 21:16
поделиться

вы всегда можете использовать memset:

int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
1
ответ дан 23 November 2019 в 21:16
поделиться

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

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

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

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

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

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

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

std::vector<int> myInts(100, 0);  // creates a vector of 100 ints, all set to zero
7
ответ дан 23 November 2019 в 21:16
поделиться

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

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

-1
ответ дан 23 November 2019 в 21:16
поделиться

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

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

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

Использование функции std :: memset из

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

Использование алгоритма std :: fill_n из ] <алгоритм>

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
23
ответ дан 23 November 2019 в 21:16
поделиться

Возможно, признак вашего случая использует __ места __

, Например, , гнездо имеет __ места __ , таким образом, это не может быть солео

, Вы должны определить, какой признак вызывает ошибку, и напишите свое собственное __ getstate __ и __ setstate __ для игнорирования этого атрибута

-121--1391376-

Да:

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

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

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

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

6
ответ дан 23 November 2019 в 21:16
поделиться

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

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

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

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

2
ответ дан 23 November 2019 в 21:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: