Я только начинаю входить в C++, и я хочу перенять некоторые хорошие привычки. Если я только что выделил массив типа int
с new
оператор, как я могу инициализировать их всех к 0 без цикличного выполнения через них всех сам? Если я просто использую memset
? Существует ли “C++” способ сделать это?
Это на удивление малоизвестная функция C ++ (о чем свидетельствует тот факт, что никто еще не дал этого в качестве ответа), но на самом деле у нее есть специальный синтаксис для инициализации массива значением:
new int[10]();
Обратите внимание, что вы должен использовать пустые круглые скобки - вы не можете, например, использовать (0)
или что-то еще (поэтому это полезно только для инициализации значения).
Это явно разрешено ISO C ++ 03 5.3.4 [expr.new] / 15, в котором говорится:
Новое-выражение, которое создает объект типа
T
, инициализирует этот объект следующим образом:...
- Если новый инициализатор имеет форму
()
, элемент инициализируется значением (8.5);
и не ограничивает типы для что это разрешено, тогда как форма (список-выражений)
явно ограничена дальнейшими правилами в том же разделе, так что она не допускает типов массивов.
Возможно, атрибут вашего экземпляра использует _ _ slots _ _
Например, socket
имеет _ _ slots _ _
, поэтому его нельзя выбрать
Необходимо определить, какой атрибут вызывает ошибку, и записать свой собственный
_ _ getstate _ _
и _ _ setstate _ _
для игнорирования этого атрибута
Да:
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 (на самом деле нет другого способа сделать это, запрещая специальную архитектуру с поддержкой аппаратного уровня).
вы всегда можете использовать memset:
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
Если выделяемая вами память является классом с конструктором, который делает что-то полезное, оператор 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
Обычно для динамических списков элементов используется std :: vector
.
Обычно я использую memset или цикл для динамического выделения необработанной памяти, в зависимости от того, насколько изменчивой будет эта область кода в будущем.
Существует ряд методов для выделения массива внутреннего типа, и все они верны, хотя какой из них выбрать, зависит ...
Ручная инициализация всех элементов в цикле
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
Возможно, признак вашего случая использует __ места __
, Например, , гнездо
имеет __ места __
, таким образом, это не может быть солео
, Вы должны определить, какой признак вызывает ошибку, и напишите свое собственное
__ getstate __
и __ setstate __
для игнорирования этого атрибута
Да:
std::vector<int> vec(SIZE, 0);
Используйте вектор вместо динамически выделенного массива. Преимущества включают в себя отсутствие необходимости в явном удалении массива (он удаляется, когда вектор выходит из области действия), а также автоматическое удаление памяти, даже если возникает исключение.
Изменить: Чтобы избежать дальнейших приводных голосов от людей, которые не удосуживаются прочитать комментарии ниже, я должен дать более ясно понять, что этот ответ не говорит, что вектор всегда правильный ответ. Но это больше способ C++, чем «вручную», чтобы убедиться, что удалить массив.
Теперь с C++ 11 также существует массив std::, моделирующий массив постоянного размера (vs вектор, который способен расти). Существует также std::unique_ptr, который управляет динамически выделенным массивом (который может сочетаться с инициализацией, как указано в других ответах на этот вопрос). Любой из них является более C++ способом, чем ручная обработка указателя на массив IMHO.
std :: fill
- односторонний. Принимает два итератора и значение для заполнения области. Это или цикл for (я полагаю) был бы более подходящим для C ++.
В частности, для установки массива примитивных целочисленных типов на 0 подходит memset
, хотя это может вызвать недоумение. Рассмотрим также calloc
, хотя его немного неудобно использовать из C ++ из-за приведения типов.
Со своей стороны, я почти всегда использую цикл.
(Я не люблю сомневаться в намерениях людей, но верно, что std :: vector
при прочих равных условиях предпочтительнее использования new []
.)