Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.52/64: Рейтинг темы: голосов - 64, средняя оценка - 4.52
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135

Можно ли обойти динамический массив не зная его размер?

11.04.2016, 02:13. Показов 14338. Ответов 79
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Массив ниже. 
Есть ли способ обойти такой массив используя указатель pArr на него? Не используя count.
 
    int count = 7;
    
    int *pArr = new int[count];
    
    int id = 0;
    while (id < count)
    {
        int value;
        cout << "pArr[" << id << "]=";
        cin >> value;
        pArr[id] = value;
        id++;
    }
    
    delete pArr;
        
    _getch();
    return 0;
1
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
11.04.2016, 02:13
Ответы с готовыми решениями:

Как создать двумерный динамический массив не зная его размеров?
Привет. Не смог найти в гугле как можно создать двумерный динамический массив не зная его длины вообще. Нашел только создание...

Можно ли создать массив, изначально не зная его размерности?
Доброго времени суток. Формируется некая последовательность (https://www.cyberforum.ru/pascalabc/thread1962554.html#post10342225) Нужно...

Можно ли задать массив, не зная заранее его длину?
Доброе утро всем. Вчера начал читать &quot;главу 4 Массивы&quot;. Там предложили 2 варианта объявления массива: 1) неинициализированный int...

79
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
12.04.2016, 12:02
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Это только один из многих возможных способов работы менеджера кучи.
А слово "может" там для красоты, да?
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Опять же если выделяем память под один экземпляр пользовательского типа хвост никуда не денется, размер все равно нужон,либо не размер а пометка номера типа.
Определение типа удаляемого объекта выводится из статического типа указателя.
См. стандарт, там об этом сказано!
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
12.04.2016, 12:09
Цитата Сообщение от Croessmah Посмотреть сообщение
Определение типа удаляемого объекта выводится из статического типа указателя.
Так вроде бы в T* a;, где T* - тип переменой, а T - так называемый базовый тип. Тоесть в типе указателя уже есть тип объекта на который он ссылается. так ведь?
0
 Аватар для Fulcrum_013
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
12.04.2016, 12:10
Цитата Сообщение от Croessmah Посмотреть сообщение
Определение типа удаляемого объекта выводится из статического типа указателя.
Из этого выводится тип деструктора который вызывать. А какого размера блок памяти при этом высвобождать а тем более как помечать свободные/пустые блоки это менеджеру кучи виднее, но ни как ни комитету по стандартизации. Опять же, виртуальный деструктор берется из VMT указатель на которую находится по отрицательному смещению.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
12.04.2016, 12:20
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Тоесть в типе указателя уже есть тип объекта на который он ссылается. так ведь?
Да.
Опять же, по ссылке выше видно, что delete можно обмануть,
правда при этом получим неопределенное поведение
5.3.5 Delete
...
3. In the first alternative (delete object ), if the static type of the object to be deleted is different from its
dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the
static type shall have a virtual destructor or the behavior is undefined. In the second alternative ( delete
array ) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
Добавлено через 33 секунды
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
А какого размера блок памяти при этом высвобождать а тем более как помечать свободные/пустые блоки это менеджеру кучи виднее, но ни как ни комитету по стандартизации.
Этим занимается operator new, а не new-expression.
А как там эти тапки реализованы - не важно,
с точки зрения c++ разницы нет, важно лишь поведение.

Добавлено через 2 минуты
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Опять же, виртуальный деструктор берется из VMT указатель на которую находится по отрицательному смещению.
Это дело реализации. Например, в первых версиях CFRONT vptr был в конце объекта, а не вначале.
И виртуальность деструктора можно вывести из статического типа => решить как действовать можно на этапе компиляции. Никакой оверхед по памяти не нужен для этого.

Добавлено через 2 минуты
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
А какого размера блок памяти при этом высвобождать а тем более как помечать свободные/пустые блоки это менеджеру кучи виднее, но ни как ни комитету по стандартизации.
Еще раз - стандарт описывает поведение (то есть что должен делать), а не реализацию (как должен делать).
3
 Аватар для Fulcrum_013
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
12.04.2016, 12:32
Цитата Сообщение от Croessmah Посмотреть сообщение
Никакой оверхед по памяти не нужен для этого.
информация для оператора typeid все равно должна хранится где то вместе с объектом.

Добавлено через 2 минуты
для объектов размером больших 8 байт экономичнее по памяти пользовать заголовок с размером, чем побайтовую карту распределения.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
12.04.2016, 14:04
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Компилятор его не знает. Но его обязан знать менеджер кучи.
То есть менеджер кучи не часть компилятора? Под компилятором понимаю в данном случае среду С++ а не часть среды разработки. Думаю, Вы говорите то же что и я.
Цитата Сообщение от Croessmah Посмотреть сообщение
Как правило,
В том то и дело что это не стало частью стандарта.
Цитата Сообщение от mimicria Посмотреть сообщение
Не утверждается, а действительно так.
То есть, если "утверждается", то это действительно не так? В чём Вы видите своё уточнение? Или Вы считаете что всё что утверждается авторитетами C++, это сомнительно?
Цитата Сообщение от mimicria Посмотреть сообщение
Попробуйте сами:
Именно сам я и пробовал. Иначе не стал бы оживлять тему данным вопросом.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
12.04.2016, 14:12
Цитата Сообщение от IGPIGP Посмотреть сообщение
В том то и дело что это не стало частью стандарта.
Разве в этом есть что-то плохое?
0
 Аватар для Fulcrum_013
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
12.04.2016, 14:56
Цитата Сообщение от IGPIGP Посмотреть сообщение
То есть менеджер кучи не часть компилятора?
Менеджер кучи это часть исполняемой программы, вшитая туда компилятором. т.е. фактически реализация функций malloc calloc realloc free и основанных на них операторов new, new[], delete, и delete[]

Добавлено через 1 минуту
Цитата Сообщение от Croessmah Посмотреть сообщение
Разве в этом есть что-то плохое?
Это просто прекрасно. потому что позволяет реализовывать разные модели менеджера памяти с учетом особенностей конкретного таргета и/или программы.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
12.04.2016, 17:00
Цитата Сообщение от Croessmah Посмотреть сообщение
Разве в этом есть что-то плохое?
Это не позволяет ответить на вопрос темы:-"Да, можно.".
Croessmah, я помню эту историю. Вообще, терминатор это весело если размер нужен для итерирования. А если он для другого нужен? Для копирования, например? Всё равно нужно пробежать до конца, чтобы размер узнать?
Ты говоришь, - пойти в хвост и найти. Но это значит:
1. Нужно бежать до хвоста. Но если ты знаешь где, то зачем бежать? Значит не знаешь и бежишь "пока не хвост". То есть это история про хвост терминатор?
2. Если хвост, это хвост терминатор, то это значит что хвост должен как-то уж очень отличаться от не хвоста. А это как?

Нежелание отвести место под размер массива в его начале, было продиктовано желанием сохранить обратную совместимость с С-массивами. Тут слово массивы в общем смысле.
Ну а то, что для коротких целых типов не хватало места для записи в одном элементе и пришлось бы выделять, скажем 4-ре или более (от реализации) байт, это означало бы рост накладных расходов для очень коротких массивов. Для сохранения общности алгоритмов пришлось бы выделять несколько экземпляров места и для пользовательских типов, возможно.
Может я не точно помню, но вроде такое, то-то читал.
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Менеджер кучи это часть исполняемой программы, вшитая туда компилятором.
Компилятором в широком смысле считают не только программу но и всё её программно-аппаратное окружение. Fulcrum_013, аргументируйте по сути. А то есть ощущение, что имеют место поиски неточностей. Вместо поисков понимания.
0
0 / 0 / 0
Регистрация: 12.04.2016
Сообщений: 9
12.04.2016, 17:18
Цитата Сообщение от nofx Посмотреть сообщение
Есть ли способ обойти такой массив используя указатель pArr на него?
Нет, ибо так устроен компьютер.
Если Вы не знаете, где конец, то машина и подавно.
0
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
12.04.2016, 17:49  [ТС]
Да, понял что нельзя с помощью указателей!
Без всяких терминаторов.
0
 Аватар для Fulcrum_013
2083 / 1575 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
12.04.2016, 18:09
Цитата Сообщение от IGPIGP Посмотреть сообщение
Компилятором в широком смысле считают не только программу но и всё её программно-аппаратное окружение.
Менеджер кучи это набор таблиц (или элементов разметки памяти действующих по какому то другому принципу) занятой/свободной кучи и функции которые производят с этими таблицами непосредственную работу. Т.е. функции malloc calloc realloc и free а так же все что у них под капотом.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
12.04.2016, 19:00
Лучший ответ Сообщение было отмечено IGPIGP как решение

Решение

Цитата Сообщение от IGPIGP Посмотреть сообщение
Меня вот всегда занимал вопрос удивительного отличия delete от delete []. Утверждается, что оно в том, что первый запускает деструктор для объекта по указателю где память выделялась оператором new, а второй, - для всех объектов, под которые память которые выделена оператором new[]. То есть, похоже что не просто "каждый компилятор желает знать, где сидит фазан"! Похоже, что каждый компилятор знает размер или может его узнать. Пусть память выделяется и освобождается операционной системой, по запросу программы, но конструкторы и деструкторы же не передаются? Значит информация должна где-то быть у программы?
Совершенно верно. Условно выражаясь, библиотека языка С++ надстраивает над классическим С-шным менеджером кучи еще и свой, "вложенный" менеджер кучи. Этот свой менеджер кучи следит за тем, что если у элементов выделяемого массива есть нетривиальный деструктор, то размер такого массива надо специально запомнить. В таком случае менеджер кучи С++ добавляет к размеру выделяемого блока соотв. дельту, передает новый размер менеджеру кучи С, получает блок памяти и в его начало записывает количество элементов массива. Потом, при удалении этого массива, delete [] прочитает этот размер и вызовет правильное количество деструкторов.

Но делается это только для массивов с нетривиальной деструкцией элементов. В общем же случае размер массива нигде не хранится.

Все это, конечно же, детали реализации, но традиционные релизации работают именно так.
2
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
12.04.2016, 23:08
TheCalligrapher, спасибо, это очень интересно. Где об этом можно почитать?
Вот тут пока не могу себе представить:
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
В общем же случае размер массива нигде не хранится.
У встроенных типов вроде int нет не конструкторов ни деструкторов. Как же delete[] применённый к указателю на целое узнает сколько памяти ему освободить? Дело ведь не только в запуске деструкторов. Нужно чтобы менеджер памяти отметил освобождаемую память как свободную, делая её доступной для дальнейшего использования?
0
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
12.04.2016, 23:28  [ТС]
Совершенно верно. Условно выражаясь, библиотека языка С++ надстраивает над классическим С-шным менеджером кучи еще и свой, "вложенный" менеджер кучи. Этот свой менеджер кучи следит за тем, что если у элементов выделяемого массива есть нетривиальный деструктор, то размер такого массива надо специально запомнить. В таком случае менеджер кучи С++ добавляет к размеру выделяемого блока соотв. дельту, передает новый размер менеджеру кучи С, получает блок памяти и в его начало записывает количество элементов массива. Потом, при удалении этого массива, delete [] прочитает этот размер и вызовет правильное количество деструкторов.
Я и не подозревал что все настолько запущенно...
Это...спасибо...
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
13.04.2016, 01:59
Лучший ответ Сообщение было отмечено IGPIGP как решение

Решение

Цитата Сообщение от IGPIGP Посмотреть сообщение
У встроенных типов вроде int нет не конструкторов ни деструкторов. Как же delete[] применённый к указателю на целое узнает сколько памяти ему освободить?
Вот именно: у встроенных типов вроде int нет деструкторов. По этой причине для таких типов вызов new[] превращается в тривиальный аналог malloc, а вызов delete[] превращается в тривиальный аналог free. Никаких конструкторов или деструкторов.

Т.е. для типа int * delete [] вообще ничего не делает а сразу напрямую передает управление функции освобождения сырой памяти operator delete[](void *), которая изнутри себя фактически вызывает free.

Так что вопрос сводится к тому, как free узнает, сколько памяти освободить. Очень просто узнает: malloc, когда выделял блок памяти, записал его размер куда-то (в начало блока обычно), а free просто извлекает этот размер оттуда же. Вот и все.

--------------------

Таким образом, когда вы через new []/delete [] работаете с массивом, имеющим нетривиальный деструктор в типе элемента, то типичный выделенный блок памяти будет содержать целых два кусочка невидимой служебной информации: во-первых, это будет размер блока в байтах, записанный туда malloc (для free), во-вторых, это будет размер массива в элементах, записанный туда new[] (для delete []).

Code
1
2
3
4
5
6
7
8
9
10
11
MyNonTrivialClass *p = new MyNonTrivialClass[17];
// Размер MyNonTrivialClass - 9 байт
 
+-----+-----+------+------+------
| 160 |  17 | p[0] | p[1] | ...
+-----+-----+------+------+------
   ^     ^  ^
   |     |  |
   |     |  p
   |     записано new []
   записано malloc (new [] запросил 157 байт = 17 * 9 + 4, размер выровнен до границы 16 байт)
Когда же вы работаете с массивом, не имеющим нетривиального деструктора в типе элемента, то типичный выделенный блок памяти будет выглядеть чисто по Сишному: в нем содержится только один кусочек невидимой служебной информации - размер блока в байтах, записанный туда malloc (для free).

Code
1
2
3
4
5
6
7
8
9
10
11
int *p = new int[17];
// Размер MyNonTrivialClass - 4 байт
 
+-----+------+------+------
|  80 | p[0] | p[1] | ...
+-----+------+------+------
   ^  ^
   |  |
   |  p
   |    
   записано malloc (new [] запросил 68 байт = 17 * 4, размер выровнен до границы 16 байт)
--------------------

Например, вот такая простая программка покажет нам эти значения в GCC

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
 
struct NonTrivial
{
  int i = 5;
  ~NonTrivial() { std::cout << "Destructor" << std::endl; }
};
 
struct Trivial
{
  int i = 5;
};
 
int main()
{
  NonTrivial *p = new NonTrivial[29];
  std::cout << *((size_t *) p - 1) << std::endl;
  std::cout << *((size_t *) p - 2) << std::endl;
  std::cout << *((size_t *) p - 3) << std::endl << std::endl;
  
  Trivial *t = new Trivial[29];
  std::cout << *((size_t *) t - 1) << std::endl;
  std::cout << *((size_t *) t - 2) << std::endl;
  std::cout << *((size_t *) t - 3) << std::endl << std::endl;
  
  int *q = new int[29];
  std::cout << *((size_t *) q - 1) << std::endl;
  std::cout << *((size_t *) q - 2) << std::endl;
  std::cout << *((size_t *) q - 3) << std::endl << std::endl;
}
Code
1
2
3
4
5
6
7
8
9
10
11
29
129
0
 
121
0
5
 
121
5
5
Для new NonTrivial[29]:
29 - это сохраненный new[] размер массива
129 - это сохраненный malloc размер блока (с внутренними накрутками)

Для new Trivial[29]:
Размер массива не сохраняется вообще
121 - это сохраненный malloc размер блока (с внутренними накрутками)

Для new int[29]:
Размер массива не сохраняется вообще
121 - это сохраненный malloc размер блока (с внутренними накрутками)

http://ideone.com/1weAK4
15
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
13.04.2016, 02:51
TheCalligrapher, огромное спасибо! Вот за что наш форум, просто нельзя не любить. Такие вещи найти очень трудно.
TheCalligrapher, то есть компилятор всё же знает размер и для тривиальных и для не тривиальных блоков. Причём для нетривиальных пишется и размер в элементах, чтобы выравнивание не мешало.
Но для встроенных типов выравнивание же не может быть? Это значит, что зная размер блока всегда можно точно и быстро посчитать размер в элементах? Почему же не реализована возможность определения длины?
Конечно, ситуация острая в том смысле, что указатель может не указывать на начало и тогда прочтётся бог знает, что. Но пусть каждый отвечает за то что он делает. Зачем опекать?
А как сохранить размер для массива short (2 bytes) если размер блока больше 65535 ?
Для win32 размер индекса ограничивается максимумом для size_t (Uint32) то есть 4 294 967 295.
В два байта не влезет же?
Или размер служебной записи не равен длине элемента? Можно предположить что его и выбирают как длину типа для индексирования. Да?
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
13.04.2016, 03:48
Лучший ответ Сообщение было отмечено IGPIGP как решение

Решение

Цитата Сообщение от IGPIGP Посмотреть сообщение
TheCalligrapher, то есть компилятор всё же знает размер и для тривиальных и для не тривиальных блоков. Причём для нетривиальных пишется и размер в элементах, чтобы выравнивание не мешало.
Это уже вопрос терминологии.

Выбор структуры блока на уровне new[]/delete[] (т.е. писать или не писать размер массива) - это действительно функциональность уровня компилятора, ибо решение принимается в зависимости от наличия у элементов массива нетривиального деструктора.

Структура же блока на уровне malloc/free - это функциональность уровня библиотеки, о которой компилятор не знает и знать не может.

Тут еще не следует забывать, что компилятор не вызывает напрямую именно malloc и free для выделения/освобождения сырой памяти. Компилятор вызывает функции operator new[] и operator delete[] для выделения/освобождения сырой памяти (а уж они, в умолчательном варианте, вызывают malloc и free или какие-то их аналоги). Пользователь имеет полное право заместить operator new[] и operator delete[] своим версиями и выделать память своими средствами со своим внутренним форматом хранения служебных данных об общем размере блока. Компилятор не хочет и не может ничего знать об этом внутреннем формате.

Цитата Сообщение от IGPIGP Посмотреть сообщение
Но для встроенных типов выравнивание же не может быть?
Это почему это? Во-первых, выравнивание по границе памяти важно в первую очередь именно для встроенных типов. Во-вторых, выравнивание размеров выделяемых в динамической блоков делается не только для выравнивания данных, но и для уменьшения фрагментации памяти. (Да и еще по всяким эвристическим/эмпирическим причинам.)

Если вы сделаете new char[3] вы практически всегда можете быть уверенными, что фактически вам будет выделен блок памяти размером [намного] более 3 байтов.

Цитата Сообщение от IGPIGP Посмотреть сообщение
Это значит, что зная размер блока всегда можно точно и быстро посчитать размер в элементах?
Нет, в общем случае даже для встроенных типов деление размера блока на размер элемента массива приведет к завышенным результатам.

Цитата Сообщение от IGPIGP Посмотреть сообщение
А как сохранить размер для массива short (2 bytes) если размер блока больше 65535 ?
Для win32 размер индекса ограничивается максимумом для size_t (Uint32) то есть 4 294 967 295.
В два байта не влезет же?
Или размер служебной записи не равен длине элемента? Можно предположить что его и выбирают как длину типа для индексирования. Да?
Именно так. Размер служебных полей для хранения этой информации обычно фиксирован и никак не зависит от размера блока и/или размера единичного элемента массива. Т.е., к примеру, размеры всегда хранятся в служебном поле типа size_t и точка.
5
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
13.04.2016, 09:08
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если вы сделаете new char[3] вы практически всегда можете быть уверенными, что фактически вам будет выделен блок памяти размером [намного] более 3 байтов.
Про char забыл
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Нет, в общем случае даже для встроенных типов деление размера блока на размер элемента массива приведет к завышенным результатам.
Хм... Это объясняет всё.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Именно так. Размер служебных полей для хранения этой информации обычно фиксирован
Спасибо. Это просто класс, TheCalligrapher.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
03.03.2020, 04:43
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Таким образом, когда вы через new []/delete [] работаете с массивом, имеющим нетривиальный деструктор в типе элемента, то типичный выделенный блок памяти будет содержать целых два кусочка невидимой служебной информации: во-первых, это будет размер блока в байтах, записанный туда malloc (для free), во-вторых, это будет размер массива в элементах, записанный туда new[] (для delete []).
В дополнение к вышенаписанному:

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

Другая причина, которую я забыл упомянуть: наличие в классе перегруженного оператора вида

C++
1
void operator delete[](void *ptr, std::size_t size)
то есть перегруженного operator delete[], в котором присутствует второй параметр типа std::size_t. В такой ситуации компилятор обязан использовать этот оператор для освобождения массивов объектов данного класса и в качестве аргумента для второго параметра size передавать тот же самый размер, который передавался в operator new[] при выделении памяти для массива.

Чтобы восстановить это значение точно, реализации нужно знать точный размер массива (количество элементов). Поэтому при появлении в классе такого перегруженного operator delete[] реализации обычно тоже тут же начинают сохранять точный размер массива в выделенном блоке памяти.

См. обновленный пример: http://coliru.stacked-crooked.... b1aad47d57

При этом компилятор MSVC++ даже в версии 2019 содержит баг: он понимает, что при наличии в классе нетривального деструктора, следует сохранить в блоке памяти фактический размер массива, а вот наличие такого operator delete[] не приводит MSVC++ к тем же выводам. Сохранения размера массива не происходит и при вызове такого operator delete[] через второй параметр передается какое-то бессмысленное значение. Это является грубым нарушением требований языка.
4
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
03.03.2020, 04:43
Помогаю со студенческими работами здесь

Как правильно передать динамический массив в функцию, увеличивающую его размер, чтобы изменения сохранились
Извиняюсь за совсем нубский вопрос, похожее не нашел. Простая учебная задача - написать функцию, которая добавляет элемент в динамический...

Создать динамический массив, размер которого пользователь вводит с клавиатуры.Заполнить его случайными числами
Кто знает, как на С++: создать динамический массив, размер которого пользователь вводит с клавиатуры. Заполнить его случайными числами из...

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

создать массив с нулями и единицами в шахматном порядке, что бы его размер можно было вводить с клавиатуры
Помогите пожалуйста

Рассчитать размер 1 пикселя в мм на мониторе,зная диагональ монитора в дюймах и его разрешения
Рассчитать размер 1 пикселя в мм на мониторе,зная диагональ монитора в дюймах и его разрешения


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
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, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru