Я только начинаю входить на С ++, и я хочу забрать хорошие привычки. Если я только что выделил массив типа int
с оператором new
, как я могу инициализировать их все до 0, не пропуская их через все? Должен ли я просто использовать memset
? Есть ли способ сделать это? “ C++ ”?Как инициализировать память новым оператором в C++?
ответ
Это удивительно малоизвестная особенность C++ (о чем свидетельствует тот факт, что никто не дал это как ответ еще), но это на самом деле имеет специальный синтаксис для default- инициализирует массив (ну, технически, это называется «значение инициализации» в стандарте):
new int[10]();
Обратите внимание, что вы должны использовать пустые круглые скобки - вы не можете, например, использовать (0)
или любое другое выражение (вот почему это полезно только для initia по умолчанию лизация).
Это явно разрешено ISO C++ 03 5.3.4 [expr.new]/15, в котором говорится:
новое выражение, которое создает объект типа T инициализирует этот объект следующим :
...
- Если новый-инициализатор имеет форму(), элемент инициализируется значением (8.5);
и не ограничивает типы, для которых это разрешено, в то время как (expression-list)
форма явно ограничено дополнительными правилами в той же секции таким образом, что оно не допускает типов массивов.
Хотя я согласен с тем, что это малоизвестно, я не могу (полностью) согласиться с тем, что это действительно очень удивительно - он был добавлен в C++ 03, который, по-видимому, почти игнорируется большинством людей (поскольку это был один из немногих новых вещи, которые он добавил). –
@ Джерри: Я должен признать, что я еще не знал (вероятно, потому, что, когда я дочитал стандарт, это уже был C++ 03). Тем не менее, замечательно, что все реализации, которые я знаю, поддерживают это (я думаю, это потому, что это так тривиально реализовать). –
Да, это довольно тривиально реализовать. Что касается новой, * all * "инициализация значения" была новой в C++ 03. –
Да есть:
std::vector<int> vec(SIZE, 0);
Использование вектора вместо динамически выделяемого массива. Преимущества включают в себя необходимость не беспокоить явным удалением массива (он удаляется, когда вектор выходит за пределы области), а также что память автоматически удаляется, даже если есть исключение.
Редактировать: Чтобы избежать дальнейшего прохода вниз от людей, которые не удосужились читать комментарии ниже, я должен сделать более понятным, что этот ответ не говорит о том, что вектор всегда правильный ответ. Но это, безусловно, более C++, чем «вручную», чтобы удалить массив.
Теперь с C++ 11 существует также std :: array, который моделирует массив с постоянным размером (вектор vs, который может расти). Существует также std :: unique_ptr, который управляет динамически распределенным массивом (который может быть объединен с инициализацией, как ответили на другие ответы на этот вопрос). Любой из них является более C++ способом, чем ручная обработка указателя на массив, IMHO.
это не отвечает на вопрос, который был задан. –
Должен ли я всегда использовать 'std :: vector' вместо динамически распределенных массивов? Каковы преимущества использования массива над вектором и наоборот? – dreamlax
Я должен был упомянуть в своем вопросе, что массив должен сохраняться после текущей области. Должен ли я использовать 'new std :: vector'? – dreamlax
Предполагая, что вы действительно хотите массив и не станд :: вектор, то «путь C++» был бы это
#include <algorithm>
int* array = new int[n]; // Assuming "n" is a pre-existing variable
std::fill_n(array, n, 0);
Но следует помнить, что под капотом это все еще на самом деле просто цикл, присваивает каждому элементу 0 (нет другого способа сделать это, за исключением специальной архитектуры с поддержкой аппаратного уровня).
Я не против, если цикл реализован под функцией, я просто хотел знать, должен ли я сам реализовать такой цикл. Спасибо за совет. – dreamlax
Вы можете быть удивлены. Я был. На моем STL (как GCC, так и Dinkumware) std :: copy фактически превращается в memcpy, если обнаруживает, что он вызывается со встроенными типами. Я не удивлюсь, если std :: fill_n использует memset. –
Nope. Используйте «Value-Initialization», чтобы установить всех членов в 0. –
std::fill
- один способ. Принимает два итератора и значение для заполнения региона. Это, или цикл for, будет (я полагаю) быть более C++ способом.
Для установки массива примитивных целочисленных типов на 0 конкретно memset
в порядке, хотя он может поднять брови. Рассмотрим также calloc
, хотя это немного неудобно использовать из C++ из-за приведения.
С моей стороны, я почти всегда использую цикл.
(я не люблю предугадывать намерения людей, но это правда, что std::vector
есть, при прочих равных условиях, предпочтительно с использованием new[]
.)
Обычно для динамических списков элементов, вы используете std::vector
.
Обычно я использую memset или цикл для динамического распределения сырой памяти в зависимости от того, как переменная я ожидаю, что область кода будет в будущем.
Если память, которую вы выделяете, представляет собой класс с конструктором, который делает что-то полезное, оператор new вызовет этот конструктор и опустит ваш объект.
Но если вы назначаете POD или что-то, у которого нет конструктора, который инициализирует состояние объекта, тогда вы не можете выделить память и инициализировать эту память оператором new за одну операцию.Однако у вас есть несколько вариантов:
1) Вместо этого используйте переменную стека. Можно выделить и default-initialize за один шаг, как это:
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
вы всегда можете использовать MemSet:
int myArray[10];
memset(myArray, 0, 10 * sizeof(int));
Я понимаю, что я могу использовать 'memset', но я не был уверен, что это был способ C++ для решения этой проблемы. – dreamlax
Yup, memset работает так же хорошо, как и в C++, как в C для установки линейной памяти на значение. –
На самом деле это не «путь на С ++», но и не массивы. –
Существует ряд методов выделить массив собственного типа и все эти метода являются правильными, хотя какой из них выбрать, зависит ...
Ручная инициализация всех элементов в цикле
int* p = new int[10];
for (int i = 0; i < 10; i++)
{
p[i] = 0;
}
Используя функцию std::memset
из <cstring>
int* p = new int[10];
std::memset(p, 0, 10);
Использование алгоритма std::fill_n
от <algorithm>
int* p = new int[10];
std::fill_n(p, 10, 0);
Использование std::vector
контейнера
std::vector<int> v(10); // elements zero'ed
Еслидоступны, используя initializer list функции
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
- 1. Проблемы с C++ 'новым' оператором?
- 2. Уточнение: что делает «новым» оператором в C++
- 3. Использование оператора = в сочетании с новым оператором
- 4. Разница между новым оператором в C++ и нового оператора в Java
- 5. memset, memcpy с новым оператором
- 6. классы с деструктором и новым оператором.
- 7. Как связать операторов RxJS5 с новым оператором?
- 8. Понимание классов шаблонов в C++ - проблема с новым оператором
- 9. Восстановить память, выделенную оператором new()?
- 10. Что касается области видимости в C++ с новым оператором
- 11. возвращает выровненную память с новым?
- 12. Как инициализировать динамическую память нестандартным способом в C++?
- 13. Как инициализировать SDL_Color в C?
- 14. Стоп-кадр разворачивается с новым оператором
- 15. Невозможно понять инструкцию java с новым оператором
- 16. Inject не работает с новым оператором
- 17. Проблема обработки массива, созданного с новым оператором
- 18. Как требуется работа с новым оператором в node.js?
- 19. C++ Разница между новым символом [size] и новым символом [size]()
- 20. Инициализировать память с помощью nan в C++ для отладки
- 21. C++ конструктор с новым
- 22. Удалить элементы из вектора указателей и освободить динамическую память, ранее выделенную новым оператором?
- 23. Разница в инициализации массива с новым оператором и без него
- 24. как перезаписать пустые значения в столбце таблицы с новым значением с новым оператором вставки
- 25. Что значит инициализировать память до нуля в C?
- 26. инициализировать компонент с новым экземпляром объекта
- 27. инициализировать фрагмент с новым именем класса
- 28. Удалит команду очистить память, выделенную новым?
- 29. Вызывает оператор удаления в памяти, выделенной новым оператором undefined оператора []?
- 30. В чем разница между новым оператором и Class.newInstance()?
Если вы хотите выбрать хорошую привычку на C++, тогда не используйте массивы напрямую и вместо этого используйте вектор. Vector будет инициализировать все элементы независимо от типа, а затем вам не нужно будет вызывать оператор delete []. – brianegge
@brianegge: Что делать, если мне нужно передать массив внешней функции C, могу ли я просто дать ему вектор? – dreamlax
Вы можете передать '& vector [0]'. – jamesdlin