Re[2]: как работает delete []ptr?
От: epflorov Россия www.epflorov.hotbox.ru
Дата: 15.07.02 18:34
Оценка:
Здравствуйте Андрей Тарасевич, Вы писали:

АТ>Здравствуйте epflorov, Вы писали:


E>>Тема http://www.rsdn.ru/forum/message.asp?mid=72857
Автор:
Дата: 15.07.02
напомнила мне о следующем.


E>>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива.


АТ>Не понимаю вопроса. Мы действительно не можем знать размер массива. А компилятор — может. Деструкторы-то вызывает компилятор, а не мы.


Логика: мы не можем ..., а компилятор — может, меня и смутила.
Вопрос произошел от указанной темы об определении размера массива, поэтому и стало интересно, кто чего может. То есть я перефразировал бы свою мысль следующим образом: почему компилятор имеет средства для определения размера массива (то есть количества элементов), а программа таких стандартных средств не имеет.

Буду очень признателен, если вы ответите на этот вопрос.

Евгений Флоров.
Евгений Флоров
Нельзя определить размер динам. массива, хотя delete[] есть
От: Андрей Тарасевич Беларусь  
Дата: 15.07.02 19:11
Оценка: 84 (7)
#Имя: FAQ.cpp.arraysize
E>Логика: мы не можем ..., а компилятор — может, меня и смутила.
E>Вопрос произошел от указанной темы об определении размера массива, поэтому и стало интересно, кто чего может. То есть я перефразировал бы свою мысль следующим образом: почему компилятор имеет средства для определения размера массива (то есть количества элементов), а программа таких стандартных средств не имеет.

Я совсем недавно отвечал на точно такой же вопрос в comp.lang.c++:

http://groups.google.com/groups?selm=3D2397A3.96BDDFED%40hotmail.com

Еще раз и по-русски:

Компилятор совсем не обязательно имеет средства для определения размера массива, выделенного в динамической памяти. Он компилятора требуется только то, чтобы он умел правильно выделять такие массивы при помощи 'new[]' и правильно уничтожать такие массивы при помощи 'delete[]'. Как компилятор это делает и какая дополнительная информация понадобится для этого компилятору и понадобится ли она вообще — личное дело компилятора. Классическим примером такой дополнительной информации является количество сконструированных элементов в массиве, которое нужно, например, для того, чтобы правильно выполнить деструкцию элементов массива. Если компилятору эта информация нужна только для того и только для того, чтобы вызвать правильное количество деструкторов, то сразу приходит на ум очевидная оптимизация: если хранимые в массиве объекты не имеют деструкторов (т.е. не являются экземплярами классов) или имеют тривиальные деструкторы (т.е. фактически тоже не имеют деструкторов), то знать количество элементов в массиве компилятору совершенно незачем, и формировать и хранить это количество нигде не надо. Эту оптимизацию используют многие компиляторы, включая MSVC и GCC.

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

Во-вторых, для единообразия, пришлось бы поддержать эту функциональность и для статических и автоматических массивов, что тоже несколько противречит общему духу встроенных С/С++ массивов.

Все это, на мой взгляд, выглядит совершенно не нужно. Особенно если учесть, что пользователь при выделении массива держал в руках его размер и мог сам позаботиться о сохранении этого размера для дальнейшего использования.
Best regards,
Андрей Тарасевич
Re[2]: Вы не правы.
От: jazzer Россия Skype: enerjazzer
Дата: 18.07.02 11:36
Оценка:
Здравствуйте Gi, Вы писали:

Gi>Здравствуйте epflorov, Вы писали:


E>>Здравствуйте.


E>>Тема http://www.rsdn.ru/forum/message.asp?mid=72857
Автор:
Дата: 15.07.02
напомнила мне о следующем.


E>>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива.

E>>то есть

E>>
E>>...
E>>int i = 100;
E>>foo *ptr = new foo[i];
E>>...
E>>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>>


E>>Евгений Флоров


Gi>кол-во элементов = размер выделенной памяти/sizeof(foo), и то и другое компилеру известно.


Как раз ему это в общем случае при использовании new неизвестно.
Например, i может быть введено пользователем в runtime.
А размер выделенной памяти ему не известен, потому что компилятор не занимается выделением памяти,
а вызывает operator new, который, в свою очередь, в общем случае дергает операционную систему,
а сколько она выделит памяти, никто не знает.

Ему все это известно только для статических массивов. (А если неизвестно, то программаа просто не скомпилируется.)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Да не знает этого компилятор!
От: jazzer Россия Skype: enerjazzer
Дата: 18.07.02 11:41
Оценка:
Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте epflorov, Вы писали:


E>>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива.

E>>то есть

E>>
E>>...
E>>int i = 100;
E>>foo *ptr = new foo[i];
E>>...
E>>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>>


Kaa>Проблема то вся в том и есть, что мы — не компилятор. Мы не знаем, а он знает. А хранит он это в некотором заголовке к выделенной памяти, т.е. выделяется на самом деле не n байт, а n + размер заголовка, и туда складывается инфа о таких вещах, как размер выделяемого блока, и, возможно, еще что-то. Таким образом, образуется некоторый overhead, зато информация присутствует и доступна в любой момент.


Компилятор ничего не знает, кроме sizeof(foo) и того, что память, освобождаемая при помощи delete[], (должна быть) выделена динамически.
Пример:
int i;
cout << "enter i:";
cin >> i;
foo *ptr = new foo[i];
...
delete[] ptr;
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: Компилятор ничего не знает
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 18.07.02 11:50
Оценка:
Здравствуйте jazzer, Вы писали:

Не надо так кричать. Обычно стандартная реализация new выделяет немного больше памяти, и в это немного больше помещается дополнительная информация (возможно, это самое i, возможно, i*sizeof(foo), это не важно), и потом, в рантайме, проверяет это значение, в котором хранится эта доп. информация.

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

j>Компилятор ничего не знает!!!


Предлагаю темой недели вынести.
Алексей Кирдин
Re[3]: Вы не правы.
От: Vi2 Удмуртия http://www.adem.ru
Дата: 18.07.02 11:54
Оценка: 2 (1)
Здравствуйте jazzer, Вы писали:

Gi>>кол-во элементов = размер выделенной памяти/sizeof(foo), и то и другое компилеру известно.


J>Как раз ему это в общем случае при использовании new неизвестно.

J>Например, i может быть введено пользователем в runtime.
J>А размер выделенной памяти ему не известен, потому что компилятор не занимается выделением памяти,
J>а вызывает operator new, который, в свою очередь, в общем случае дергает операционную систему,
J>а сколько она выделит памяти, никто не знает.

ИМХО, в runtime код выполнения вообще не знает о том, что он делает, что он выделяет память: процессор просто выполняет инструкции, и что в этот момент делается ему по барабану.
Во время компиляции компилятор тоже не знает о том, что он выделяет память — он просто транслирует некий языковый код.

Так, кто же знает, что при new A[size] происходит выделение определённого количества памяти?

Скорее всего, тот, кто писал код компилятора. Именно он составил свой код так, чтобы он размещал в стеке или ещё где всю необходимую информацию при обработке языкового выражения new A[size] и соответственно что-то вызывал.

ИТОГО: В предыдущем ответе использован слэнг программистов.

Да, именно компилятор знает количество экземпляров инстантиируемых объектов, через константу или через целочисленное выражение в скобках [], которое он и передаёт как параметр вызываемому методу new_xxxx (или использует другой механизм).

J>Ему все это известно только для статических массивов. (А если неизвестно, то программаа просто не скомпилируется.)
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Вы не правы.
От: jazzer Россия Skype: enerjazzer
Дата: 18.07.02 12:08
Оценка:
Здравствуйте Vi2, Вы писали:

Vi2>Здравствуйте jazzer, Вы писали:


Gi>>>кол-во элементов = размер выделенной памяти/sizeof(foo), и то и другое компилеру известно.


J>>Как раз ему это в общем случае при использовании new неизвестно.

J>>Например, i может быть введено пользователем в runtime.
J>>А размер выделенной памяти ему не известен, потому что компилятор не занимается выделением памяти,
J>>а вызывает operator new, который, в свою очередь, в общем случае дергает операционную систему,
J>>а сколько она выделит памяти, никто не знает.

Vi2>ИМХО, в runtime код выполнения вообще не знает о том, что он делает, что он выделяет память: процессор просто выполняет инструкции, и что в этот момент делается ему по барабану.

Vi2>Во время компиляции компилятор тоже не знает о том, что он выделяет память — он просто транслирует некий языковый код.

Vi2>Так, кто же знает, что при new A[size] происходит выделение определённого количества памяти?


Vi2>Скорее всего, тот, кто писал код компилятора. Именно он составил свой код так, чтобы он размещал в стеке или ещё где всю необходимую информацию при обработке языкового выражения new A[size] и соответственно что-то вызывал.


Vi2>ИТОГО: В предыдущем ответе использован слэнг программистов.


Vi2>Да, именно компилятор знает количество экземпляров инстантиируемых объектов, через константу или через целочисленное выражение в скобках [], которое он и передаёт как параметр вызываемому методу new_xxxx (или использует другой механизм).



В том-то и дело, что он не знает количество экземпляров инстантиируемых объектов, и никто не обязан давать ему в new именно константу. Но зато он "знает, где искать" (с) Эйнштейн.

И вообще, как мы недавно выяснили с Каа, компилятор ничего не знает

J>>Ему все это известно только для статических массивов. (А если неизвестно, то программаа просто не скомпилируется.)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Поддерживаю :) (-)
От: jazzer Россия Skype: enerjazzer
Дата: 18.07.02 12:10
Оценка:
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Компилятор ничего не знает
От: epflorov Россия www.epflorov.hotbox.ru
Дата: 18.07.02 12:16
Оценка:
Здравствуйте Kaa, Вы писали:

Kaa>Предлагаю темой недели вынести.


Это как?
Евгений Флоров
Re[5]: Всё просто, как в танке
От: Vi2 Удмуртия http://www.adem.ru
Дата: 18.07.02 12:17
Оценка:
Здравствуйте jazzer, Вы писали:

J>В том-то и дело, что он не знает количество экземпляров инстантиируемых объектов, и никто не обязан давать ему в new именно константу. Но зато он "знает, где искать" (с) Эйнштейн.


"никто не обязан давать" — сильно сказано! В том-то и дело, что тот, кто пишет код new A[size] и указывает вполне определённое выражение для size, и даёт компилятору знание. И неважно, что это не константа — компилятор-то сам не выделяет память, а инструктирует runtime-код о такой операции.

А если он (кто пишет код) ничего не укажет (раз не обязан!), то и получит ошибку компиляции. Всё просто, как в танке.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[5]: Компилятор ничего не знает
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 18.07.02 12:21
Оценка:
Здравствуйте epflorov, Вы писали:

Kaa>>Предлагаю темой недели вынести.

E>Это как?

Ну, не знаю. Творчески к этому подойти.

Вот вариант например: всю неделю отвечать на всевозможные вопросы, касающиеся работы с памятью во всех форумах вне зависимости от того, спрашивал кто-то, или нет.

Более жестко — о чем бы человек не спрашивал, отвечать ему о распределении памяти (ну, это я перегнул, я ж говорил о творчестве)
Алексей Кирдин
Re[5]: Вы не правы.
От: Gi Россия  
Дата: 18.07.02 12:24
Оценка:
Здравствуйте jazzer, Вы писали:

J>Здравствуйте Vi2, Вы писали:


Vi2>>Здравствуйте jazzer, Вы писали:


Gi>>>>кол-во элементов = размер выделенной памяти/sizeof(foo), и то и другое компилеру известно.


J>>>Как раз ему это в общем случае при использовании new неизвестно.

J>>>Например, i может быть введено пользователем в runtime.
J>>>А размер выделенной памяти ему не известен, потому что компилятор не занимается выделением памяти,
J>>>а вызывает operator new, который, в свою очередь, в общем случае дергает операционную систему,
J>>>а сколько она выделит памяти, никто не знает.

Vi2>>ИМХО, в runtime код выполнения вообще не знает о том, что он делает, что он выделяет память: процессор просто выполняет инструкции, и что в этот момент делается ему по барабану.

Vi2>>Во время компиляции компилятор тоже не знает о том, что он выделяет память — он просто транслирует некий языковый код.

Vi2>>Так, кто же знает, что при new A[size] происходит выделение определённого количества памяти?


Vi2>>Скорее всего, тот, кто писал код компилятора. Именно он составил свой код так, чтобы он размещал в стеке или ещё где всю необходимую информацию при обработке языкового выражения new A[size] и соответственно что-то вызывал.


Vi2>>ИТОГО: В предыдущем ответе использован слэнг программистов.


Vi2>>Да, именно компилятор знает количество экземпляров инстантиируемых объектов, через константу или через целочисленное выражение в скобках [], которое он и передаёт как параметр вызываемому методу new_xxxx (или использует другой механизм).



J>В том-то и дело, что он не знает количество экземпляров инстантиируемых объектов, и никто не обязан давать ему в new именно константу. Но зато он "знает, где искать" (с) Эйнштейн.


Не буду многословен, тем более что всё уже написано в соседней ветке, посмотри ответ Андрея Тарасевича, там где "ещё раз и по-русски".
Re[3]: Сермяжная правда
От: Vi2 Удмуртия http://www.adem.ru
Дата: 18.07.02 12:25
Оценка:
Здравствуйте jazzer, Вы писали:

J>Компилятор ничего не знает, кроме sizeof(foo) и того, что память, освобождаемая при помощи delete[], (должна быть) выделена динамически.

J>Пример:
int i;
J>cout << "enter i:";
J>cin >> i;
J>foo *ptr = new foo[i];
J>...
J>delete[] ptr;


Зато компилятор (как велит ему кодировщик или разработчик компилятора) знает, что по адресу &i лежит число, которое он должен передать оператору new[] для его корректной работы.

А само это число компилятор действительно не знает, да и не зачем ему оно ему?!
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[6]: Вы передергиваете или невнимательны.
От: jazzer Россия Skype: enerjazzer
Дата: 18.07.02 12:41
Оценка:
Здравствуйте Vi2, Вы писали:

Vi2>Здравствуйте jazzer, Вы писали:


J>>В том-то и дело, что он не знает количество экземпляров инстантиируемых объектов, и никто не обязан давать ему в new именно константу. Но зато он "знает, где искать" (с) Эйнштейн.


Vi2>"никто не обязан давать" — сильно сказано! В том-то и дело, что тот, кто пишет код new A[size] и указывает вполне определённое выражение для size, и даёт компилятору знание. И неважно, что это не константа — компилятор-то сам не выделяет память, а инструктирует runtime-код о такой операции.


Vi2>А если он (кто пишет код) ничего не укажет (раз не обязан!), то и получит ошибку компиляции. Всё просто, как в танке.


Вы передергиваете или невнимательны.
Я написал: "никто не обязан давать ему в new именно константу".
Я не писал: "никто не обязан ему давать что-либо".
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: В этом ключе отвечать можно так
От: jazzer Россия Skype: enerjazzer
Дата: 18.07.02 12:43
Оценка: :)
Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте epflorov, Вы писали:


Kaa>>>Предлагаю темой недели вынести.

E>>Это как?

Kaa>Ну, не знаю. Творчески к этому подойти.


Kaa>Вот вариант например: всю неделю отвечать на всевозможные вопросы, касающиеся работы с памятью во всех форумах вне зависимости от того, спрашивал кто-то, или нет.


Kaa>Более жестко — о чем бы человек не спрашивал, отвечать ему о распределении памяти (ну, это я перегнул, я ж говорил о творчестве)


В этом ключе отвечать можно так: "Object is a region of storage"
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: Каюсь, виноват
От: Vi2 Удмуртия http://www.adem.ru
Дата: 18.07.02 12:50
Оценка:
Здравствуйте jazzer, Вы писали:

J>Вы передергиваете или невнимательны.

J>Я написал: "никто не обязан давать ему в new именно константу".
J>Я не писал: "никто не обязан ему давать что-либо".

Каюсь, виноват. Передёрнул по невнимательности.
А вообще тема интересная, как при постройке Собора Парижской Богоматери — чернорабочий просто ямы роет, каменщик просто камни кладёт и т.д.. А в итоге — Собор построен.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[8]: Полностью согласен, главное - результат :) (-)
От: jazzer Россия Skype: enerjazzer
Дата: 18.07.02 12:56
Оценка:
"А в итоге — Собор построен."
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Нельзя определить размер динам. массива, хотя delete[] е
От: Яшин Евгений Новая Зеландия
Дата: 22.02.06 03:39
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ> Если компилятору эта информация нужна только для того и только для того, чтобы вызвать правильное количество деструкторов, то сразу приходит на ум очевидная оптимизация: если хранимые в массиве объекты не имеют деструкторов (т.е. не являются экземплярами классов) или имеют тривиальные деструкторы (т.е. фактически тоже не имеют деструкторов), то знать количество элементов в массиве компилятору совершенно незачем, и формировать и хранить это количество нигде не надо. Эту оптимизацию используют многие компиляторы, включая MSVC и GCC.


Попробую с вами не согласиться.
Во первых вы тут сами себе противоречите — а если объекты имеют нетривиальные деструктора? Тогда размер нужен обязательно, в этом случае вы предлагаете хранить bool нужен размер / не нужен размер? Такая оптимизация не имеет смысла.

А во вторых, не верите мне, поверьте Александреску. "Современное проектирование на C++", №4.7. Там утверждается что компилятор в любом случае имеет инфу о размере удаляемого блока и более того, её можно получить с помощью специальной перегрузки оператора:

    void operator delete(void* p, std::size_t size);
Re[2]: Нельзя определить размер динам. массива, хотя delete[
От: Андрей Тарасевич Беларусь  
Дата: 22.02.06 06:23
Оценка: 22 (3)
Здравствуйте, Яшин Евгений, Вы писали:

ЯЕ>Здравствуйте, Андрей Тарасевич, Вы писали:


АТ>> Если компилятору эта информация нужна только для того и только для того, чтобы вызвать правильное количество деструкторов, то сразу приходит на ум очевидная оптимизация: если хранимые в массиве объекты не имеют деструкторов (т.е. не являются экземплярами классов) или имеют тривиальные деструкторы (т.е. фактически тоже не имеют деструкторов), то знать количество элементов в массиве компилятору совершенно незачем, и формировать и хранить это количество нигде не надо. Эту оптимизацию используют многие компиляторы, включая MSVC и GCC.


ЯЕ>Попробую с вами не согласиться.

ЯЕ> Во первых вы тут сами себе противоречите — а если объекты имеют нетривиальные деструктора? Тогда размер нужен обязательно,

Совершенно верно. В этом случае размер нужен обязательно. И компилятор его хранит — именно в этом случае.

ЯЕ> в этом случае вы предлагаете хранить bool нужен размер / не нужен размер? Такая оптимизация не имеет смысла.


Ничего подобного я не предлагаю. Факт наличия нетривиального деструктора однозначно определяется статическим типом выражения, использованного в качестве аргумента 'delete[]', т.е. известен на стадии компиляции. На основе этой инофрмации компилятор просто генерирует правильную реализацию 'delete[]': либо "нетривиальную", читающую размер и вызывающую деструкторы перед освобождением памяти, либо "тривиальную", просто сразу освобождающую память.

ЯЕ> А во вторых, не верите мне, поверьте Александреску. "Современное проектирование на C++", №4.7. Там утверждается что компилятор в любом случае имеет инфу о размере удаляемого блока и более того, её можно получить с помощью специальной перегрузки оператора:


ЯЕ>
ЯЕ>    void operator delete(void* p, std::size_t size);
ЯЕ>


Вы путаете два разных размера.

Есть доступный RTL размер выделенного блока сырой памяти в байтах. Это — размер "низкого уровня" — прямой аналог того самого размера, который используется еще сишной функцией 'free()' для блока памяти, выделенного 'malloc' (а если честно — это и есть тот самый размер, унаследованный еще из С). Именно этот размер и передается в 'operator new' и 'operator delete'.

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

Таким образом, выделяя память через 'new int[8]', мы просим и получаем от RTL блок памяти в '8 * sizeof(int)' байтов или несколько больше и RTL где-то запоминает размер этого блока. Обычно это делается в самом блоке, "слева" от возвращенного указателя, т.е. фактически размер выделенного блока будет еще, скажем, на 4 байта больше (будем считать что наша платформа использует 4 байта для хранения размера блоков сырой памяти). Запоминать же размер массива в элементах в этом случае не надо, т.к. тип 'int' не требует деструктирования.

Выделяя же память через 'new C[8]' (где C — класс с нетривиальным деструктором) в традиционной реализации мы (с точки зрения 'operator new') просим у RTL блок памяти длиной в '8 * sizeof(C) + 4' байт. Эта подсистема даст нам такой блок (или больше) не забыв запомнить его размер в байтах "слева" от возвращенного указателя. Реализация 'new[]' же использует первые 4 байта этого блока для запоминания размера массива, т.е. запишет туда 8, сконструирует в остальной памяти 8 элементов и вернет нам указатель на первый из них. Т.е. в этом случае "слева" от возвращенного указателя хранится два размера — размер массива в элементах и размер блока памяти в байтах.

Я в своем сообщении говорил именно об опциональности хранения второго размера (размера массива в элементах). А первый размер хранится всегда. Все это Александреску никак не противоречит.
Best regards,
Андрей Тарасевич
Re[3]: Нельзя определить размер динам. массива, хотя delete[
От: Яшин Евгений Новая Зеландия
Дата: 22.02.06 12:08
Оценка:
АТ>Таким образом, выделяя память через 'new int[8]', мы просим и получаем от RTL блок памяти в '8 * sizeof(int)' байтов или несколько больше и RTL где-то запоминает размер этого блока. Обычно это делается в самом блоке, "слева" от возвращенного указателя, т.е. фактически размер выделенного блока будет еще, скажем, на 4 байта больше (будем считать что наша платформа использует 4 байта для хранения размера блоков сырой памяти). Запоминать же размер массива в элементах в этом случае не надо, т.к. тип 'int' не требует деструктирования.

АТ>Выделяя же память через 'new C[8]' (где C — класс с нетривиальным деструктором) в традиционной реализации мы (с точки зрения 'operator new') просим у RTL блок памяти длиной в '8 * sizeof(C) + 4' байт. Эта подсистема даст нам такой блок (или больше) не забыв запомнить его размер в байтах "слева" от возвращенного указателя. Реализация 'new[]' же использует первые 4 байта этого блока для запоминания размера массива, т.е. запишет туда 8, сконструирует в остальной памяти 8 элементов и вернет нам указатель на первый из них. Т.е. в этом случае "слева" от возвращенного указателя хранится два размера — размер массива в элементах и размер блока памяти в байтах.


Хорошо, т.е. вы хотите сказать, что вот в таком коде

class C
{
    int v;
    ~C(){}
};

void f()
{
    C* ptr = new C[100];
    delete[] (int*)ptr;
}


компилятор просто не сможет правильно вычислить адрес начала "сырой" выделеной памяти и, попросту говоря, всё хлопнеться?
А вы сможете подтвердить такое поведение пунктом стандарта?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.