|
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
|
||||||
Можно ли обойти динамический массив не зная его размер?11.04.2016, 02:13. Показов 14338. Ответов 79
Метки нет (Все метки)
1
|
||||||
| 11.04.2016, 02:13 | |
|
Ответы с готовыми решениями:
79
Можно ли создать массив, изначально не зная его размерности? Можно ли задать массив, не зная заранее его длину? |
|
Неэпический
|
|||
| 12.04.2016, 12:02 | |||
![]() См. стандарт, там об этом сказано!
0
|
|||
|
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
|
||
| 12.04.2016, 12:09 | ||
T* a;, где T* - тип переменой, а T - так называемый базовый тип. Тоесть в типе указателя уже есть тип объекта на который он ссылается. так ведь?
0
|
||
|
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
|
||
| 12.04.2016, 12:10 | ||
|
0
|
||
|
Неэпический
|
||||||
| 12.04.2016, 12:20 | ||||||
|
Опять же, по ссылке выше видно, что delete можно обмануть, правда при этом получим неопределенное поведение
А как там эти тапки реализованы - не важно, с точки зрения c++ разницы нет, важно лишь поведение. Добавлено через 2 минуты И виртуальность деструктора можно вывести из статического типа => решить как действовать можно на этапе компиляции. Никакой оверхед по памяти не нужен для этого. Добавлено через 2 минуты
3
|
||||||
|
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
|
||
| 12.04.2016, 12:32 | ||
|
Добавлено через 2 минуты для объектов размером больших 8 байт экономичнее по памяти пользовать заголовок с размером, чем побайтовую карту распределения.
0
|
||
|
Комп_Оратор)
|
|||||
| 12.04.2016, 14:04 | |||||
0
|
|||||
|
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
|
|||
| 12.04.2016, 14:56 | |||
|
Добавлено через 1 минуту
0
|
|||
|
Комп_Оратор)
|
|||
| 12.04.2016, 17:00 | |||
![]() Croessmah, я помню эту историю. Вообще, терминатор это весело если размер нужен для итерирования. А если он для другого нужен? Для копирования, например? Всё равно нужно пробежать до конца, чтобы размер узнать? Ты говоришь, - пойти в хвост и найти. Но это значит: 1. Нужно бежать до хвоста. Но если ты знаешь где, то зачем бежать? Значит не знаешь и бежишь "пока не хвост". То есть это история про хвост терминатор? ![]() 2. Если хвост, это хвост терминатор, то это значит что хвост должен как-то уж очень отличаться от не хвоста. А это как? Нежелание отвести место под размер массива в его начале, было продиктовано желанием сохранить обратную совместимость с С-массивами. Тут слово массивы в общем смысле. Ну а то, что для коротких целых типов не хватало места для записи в одном элементе и пришлось бы выделять, скажем 4-ре или более (от реализации) байт, это означало бы рост накладных расходов для очень коротких массивов. Для сохранения общности алгоритмов пришлось бы выделять несколько экземпляров места и для пользовательских типов, возможно. Может я не точно помню, но вроде такое, то-то читал.
0
|
|||
|
0 / 0 / 0
Регистрация: 12.04.2016
Сообщений: 9
|
||
| 12.04.2016, 17:18 | ||
![]() Если Вы не знаете, где конец, то машина и подавно.
0
|
||
|
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
|
|
| 12.04.2016, 17:49 [ТС] | |
|
Да, понял что нельзя с помощью указателей!
Без всяких терминаторов.
0
|
|
|
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
|
||
| 12.04.2016, 18:09 | ||
|
0
|
||
|
Вездепух
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
|
||
| 12.04.2016, 19:00 | ||
Сообщение было отмечено IGPIGP как решение
Решениеdelete [] прочитает этот размер и вызовет правильное количество деструкторов.Но делается это только для массивов с нетривиальной деструкцией элементов. В общем же случае размер массива нигде не хранится. Все это, конечно же, детали реализации, но традиционные релизации работают именно так.
2
|
||
|
Комп_Оратор)
|
||
| 12.04.2016, 23:08 | ||
|
TheCalligrapher, спасибо, это очень интересно. Где об этом можно почитать?
Вот тут пока не могу себе представить:
0
|
||
|
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
|
||
| 12.04.2016, 23:28 [ТС] | ||
Это...спасибо...
0
|
||
|
Вездепух
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
|
||||||||||||||||||||||
| 13.04.2016, 01:59 | ||||||||||||||||||||||
Сообщение было отмечено IGPIGP как решение
Решениеint нет деструкторов. По этой причине для таких типов вызов new[] превращается в тривиальный аналог malloc, а вызов delete[] превращается в тривиальный аналог free. Никаких конструкторов или деструкторов.Т.е. для типа int * delete [] вообще ничего не делает а сразу напрямую передает управление функции освобождения сырой памяти operator delete[](void *), которая изнутри себя фактически вызывает free.Так что вопрос сводится к тому, как free узнает, сколько памяти освободить. Очень просто узнает: malloc, когда выделял блок памяти, записал его размер куда-то (в начало блока обычно), а free просто извлекает этот размер оттуда же. Вот и все.-------------------- Таким образом, когда вы через new []/delete [] работаете с массивом, имеющим нетривиальный деструктор в типе элемента, то типичный выделенный блок памяти будет содержать целых два кусочка невидимой служебной информации: во-первых, это будет размер блока в байтах, записанный туда malloc (для free), во-вторых, это будет размер массива в элементах, записанный туда new[] (для delete []).
malloc (для free).
Например, вот такая простая программка покажет нам эти значения в GCC
new NonTrivial[29]:29 - это сохраненный new[] размер массива129 - это сохраненный malloc размер блока (с внутренними накрутками)Для new Trivial[29]:Размер массива не сохраняется вообще 121 - это сохраненный malloc размер блока (с внутренними накрутками)Для new int[29]:Размер массива не сохраняется вообще 121 - это сохраненный malloc размер блока (с внутренними накрутками)http://ideone.com/1weAK4
15
|
||||||||||||||||||||||
|
Комп_Оратор)
|
|
| 13.04.2016, 02:51 | |
|
TheCalligrapher, огромное спасибо! Вот за что наш форум, просто нельзя не любить. Такие вещи найти очень трудно.
TheCalligrapher, то есть компилятор всё же знает размер и для тривиальных и для не тривиальных блоков. Причём для нетривиальных пишется и размер в элементах, чтобы выравнивание не мешало. Но для встроенных типов выравнивание же не может быть? Это значит, что зная размер блока всегда можно точно и быстро посчитать размер в элементах? Почему же не реализована возможность определения длины? Конечно, ситуация острая в том смысле, что указатель может не указывать на начало и тогда прочтётся бог знает, что. Но пусть каждый отвечает за то что он делает. Зачем опекать? А как сохранить размер для массива short (2 bytes) если размер блока больше 65535 ? Для win32 размер индекса ограничивается максимумом для size_t (Uint32) то есть 4 294 967 295. В два байта не влезет же? ![]() Или размер служебной записи не равен длине элемента? Можно предположить что его и выбирают как длину типа для индексирования. Да?
1
|
|
|
Вездепух
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
|
|||||
| 13.04.2016, 03:48 | |||||
Сообщение было отмечено IGPIGP как решение
РешениеВыбор структуры блока на уровне new[]/delete[] (т.е. писать или не писать размер массива) - это действительно функциональность уровня компилятора, ибо решение принимается в зависимости от наличия у элементов массива нетривиального деструктора.Структура же блока на уровне malloc/free - это функциональность уровня библиотеки, о которой компилятор не знает и знать не может. Тут еще не следует забывать, что компилятор не вызывает напрямую именно malloc и free для выделения/освобождения сырой памяти. Компилятор вызывает функции operator new[] и operator delete[] для выделения/освобождения сырой памяти (а уж они, в умолчательном варианте, вызывают malloc и free или какие-то их аналоги). Пользователь имеет полное право заместить operator new[] и operator delete[] своим версиями и выделать память своими средствами со своим внутренним форматом хранения служебных данных об общем размере блока. Компилятор не хочет и не может ничего знать об этом внутреннем формате.Если вы сделаете new char[3] вы практически всегда можете быть уверенными, что фактически вам будет выделен блок памяти размером [намного] более 3 байтов.size_t и точка.
5
|
|||||
|
Вездепух
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
|
|||||||
| 03.03.2020, 04:43 | |||||||
|
В традиционных реализациях существует еще одна причина, которая должна заставлять реализацию new[] записывать в выделенный блок памяти точный размер массива (количество элементов). Одной причиной, уже упомянутой выше, является наличие в классе элемента нетривиального деструктора.Другая причина, которую я забыл упомянуть: наличие в классе перегруженного оператора вида
operator delete[], в котором присутствует второй параметр типа std::size_t. В такой ситуации компилятор обязан использовать этот оператор для освобождения массивов объектов данного класса и в качестве аргумента для второго параметра size передавать тот же самый размер, который передавался в operator new[] при выделении памяти для массива.Чтобы восстановить это значение точно, реализации нужно знать точный размер массива (количество элементов). Поэтому при появлении в классе такого перегруженного operator delete[] реализации обычно тоже тут же начинают сохранять точный размер массива в выделенном блоке памяти.См. обновленный пример: http://coliru.stacked-crooked.... b1aad47d57 При этом компилятор MSVC++ даже в версии 2019 содержит баг: он понимает, что при наличии в классе нетривального деструктора, следует сохранить в блоке памяти фактический размер массива, а вот наличие такого operator delete[] не приводит MSVC++ к тем же выводам. Сохранения размера массива не происходит и при вызове такого operator delete[] через второй параметр передается какое-то бессмысленное значение. Это является грубым нарушением требований языка.
4
|
|||||||
| 03.03.2020, 04:43 | |
|
Помогаю со студенческими работами здесь
80
Как правильно передать динамический массив в функцию, увеличивающую его размер, чтобы изменения сохранились
Создать массив с нулями и единицами в шахматном порядке, что бы его размер можно было вводить с клавиатуры
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Символьное дифференцирование
igorrr37 13.02.2026
/ *
Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2).
Унарный минус обозначается как !
*/
#include <iostream>
#include <stack>
#include <cctype>. . .
|
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
|
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу,
и светлой Луне.
В мире
покоя нет
и люди
не могут жить в тишине.
А жить им немного лет.
|
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила»
«Время-Деньги»
«Деньги -Пуля»
|
|
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога
Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
|
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога
Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
|
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога
Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
|
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
|