2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2
 
 
Сообщение04.02.2008, 17:37 


21/03/06
1545
Москва
незваный гость писал(а):
e2e4 писал(а):
2. Происходит попытка занять всю доступную память для данной программы. Ну это бред по определению

Ну отчего же? Это абсолютно нормальная стратегия для встроенных систем. После или до инициализации ядра (в зависимости от используемого ядра), runtime забирает всю память и управляет ей.

Поймали на моей же проф. специализации :). Спорить не буду, однако, две ремарки:
1. Если брать встраиваемую систему с сильно ограниченным кол-вом ресурсов (микроконтроллер без внешней ОЗУ), то большинство программ там пишется вообще без какой-либо ОС. Использовать динамическое выделение памяти на такой платформе - большаааая роскошь.
2. Если встраиваемая система уже переходит некоторый уровень навороченности, например система из 100+ процессоров, с резервированием и т.п., то я предпочитаю ее рассматривать как платформу с современной ОС реального времени типа linux, с многозадачностью, и, как следствие, с динамическим выделением памяти средствами в т.ч. ОС.

незваный гость писал(а):
e2e4 писал(а):
Ибо new - это оператор, поведение которого (неперегруженного) должно оставаться предсказуемым и идентичным в рамках хотя бы данного компилятора, что не будет осуществляться при использовании иной ф-ии malloc.

Почему? Почему оно станет непредсказуемым?

Да хотя бы потому, что в один прекрасный момент некий Вася Пупкин перепишет malloc таким образом, что она вместо выделения памяти начнет в крестики-нолики играть :).
А вот в поведении оператора языка я хотел бы быть уверенным... Иначе и для int operator+(const int &, const int &) можно захотеть, чтобы он вызывал некоторую ф-ию int add(int, int). А ведь это уже совем не логично.

Повторяю, это только моя личная логика, чем руководствовались разработчики стандарта и что они туда заложили, мне не ведомо.

незваный гость писал(а):
Это несущественно. Существенно, что new вызывает конструктор, а malloc() — нет.

Считаю, что типизация не менее существенна, чем концепция ООП. Точнее, это две стороны одной медали. Про конструктор упустил, сорри, но это, конечно, подразумевается.

незваный гость писал(а):
очевидно, что new не может не взаимодействовать с malloc() — употребление их в одной программе вполне законно.

Простите, но мне это очевидным не кажется. Почему - я объяснил выше. Если Вы имеете ввиду, что сам компилятор ничего не обязан знать о целевой системе, и это дело внешних (библиотечных) функций - то, в общем случае, это неверно. И еще - в качестве такой внешней функции выделения памяти вполне может выступать какая-нибудь internal_fn_123, реализованная в какой-нибудь специфичной для данного компилятора библиотеке, и не прототипизорованная в stdlib.h.
Еще раз формулирую тезис: void * malloc ( size_t size ) и многие подобные ей функции оставлены в стандартной библиотеке Си++ только ради сохранения совместимости с Си программами. Использование в проекте одновременно и new и malloc - дурной тон и не рекомендуется.

 Профиль  
                  
 
 
Сообщение04.02.2008, 23:13 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
e2e4 писал(а):
Спорить не буду, однако, две ремарки:

А если не первая и не вторая? Скажем, всего-то дюжины полторы процессоров с ограниченными ресурсами (а бывают ли во встроенных системах неограниченные)? Как Вы «предпочитаете рассматривать» — это одно, а как писать систему — это, знаете ли, другое. Такое впечатление, что Вы идёте от учебника, а не от задачи.

e2e4 писал(а):
Да хотя бы потому, что в один прекрасный момент некий Вася Пупкин

А я перепишу new. И, поверите ли, это вполне законно. Более того, для встроенных систем это применяется очень часто: 1) чтобы указать нестандартное управление распределением памяти, и 2) чтобы блокировать попытку использования стандартного.

e2e4 писал(а):
А вот в поведении оператора языка я хотел бы быть уверенным...

Хотеть не вредно. Вредно (материально и морально) на это закладываться. Стандарт, по-моему, не запрещает.

e2e4 писал(а):
Считаю, что типизация не менее существенна, чем концепция ООП

Если бы нужна была только типизация, достаточно было бы написать: template <class T> T* talloc() { return (T*)malloc(sizeof(T)); }. И пользовать его в своё удовольствие: T* ptr = talloc<T>();. Вы, кстати, обратили внимание, что delete не типизированный?

e2e4 писал(а):
Простите, но мне это очевидным не кажется.
‹…›
Использование в проекте одновременно и new и malloc - дурной тон и не рекомендуется.

Вы опять идёте от книги, от лекции. В жизни ничего не бывает просто.

(1) Изоляция malloc() и new, конечно, возможна, но требует разделения пулов памяти, на которых они работают. Естественно, ни один разработчик библиотеки на это не идёт. А если malloc() и new работают на одном и том же пуле памяти, они не могут не знать друг о друге.

(2) Жизнь прозаичнее чеканных формулировок профессоров. Скажем, Вы купили библиотеку. Библиотека использует malloc(). И всё, Вы попались: Вы тоже используете malloc() для объектов, связанных с этой библиотекой. Вы даже делаете специальный класс, который скрывает подобные объекты, чтобы глаза не мозолили и не перепутать, как создавать/удалять. Но суть осталась: в проекте смешаны malloc() и new.

Бывают и другие ситуации, но схема событий понятна: мы не всегда владеем всем кодом в проекте. И поэтому любой разработчик С++ компилятора / библиотеки с этим считается.

P.S. В talloc() намеренно опущена обработка нехватки памяти.

 Профиль  
                  
 
 
Сообщение07.02.2008, 00:25 


21/03/06
1545
Москва
незваный гость писал(а):
e2e4 писал(а):
Спорить не буду, однако, две ремарки:

А если не первая и не вторая? Скажем, всего-то дюжины полторы процессоров с ограниченными ресурсами (а бывают ли во встроенных системах неограниченные)? Как Вы «предпочитаете рассматривать» — это одно, а как писать систему — это, знаете ли, другое. Такое впечатление, что Вы идёте от учебника, а не от задачи.

Если не первая и не вторая - тогда Вы абсолютно правы - выделять память нужно раз и навсегда. Всю. Имеющуюся в системе. Только эта практика долго не проживет, как Вы понимаете. Скоро самый мааааленьки процессор будет иметь такую вычислительную мощность и такуууую память, что наш с Вами спор станет бессмысленнен - будет ОС, будет malloc с new и т.п.

P.S. Мне трудно в данный момент писать - нахожусь в командировке по совершенно, кстати, реальной программной системе. Поэтому не смогу прокомментировать все. Прочитал Ваш ответ. Вы на 100%, абсолютно, стопудово правы. Я писал, исходя их учебника. На практике программеры мешают malloc и new, преобразуют void * к любому типу, строят разработчиков электроники... Но я себе ставлю на этом форуме задачу сформулировать то, как надо писать программы, а не то, как их пишут. Пишут - хреново. Это практика. Несколько людей думают и заботятся как написать лучше - это учебник.

Учебник, Вы считаете хуже? Ваше право. Поверьте, плохо - оно само получится. Надо планировать как лучше.

 Профиль  
                  
 
 
Сообщение07.02.2008, 03:22 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Зная теперь, что Вы в командировке, не буду думать, что Вы потеряли интерес. Просто пойдёт медленнее, и всё.

e2e4 писал(а):
Только эта практика долго не проживет, как Вы понимаете.

Не знаю. Может быть, и проживёт долго. Мне кажется, что процессоры, память дешевеют. Одновременно с этим растёт круг задач, в которых их используют. А экономика проста: программу пишут один раз, а процессор (или горсть процессоров) нужно поставить в каждый прибор. То есть, затраты по-приборно. Это, в свою очередь, приводит к тому, что пока есть предложение, ставится процессор с не более чем двухкратным запасом ресурсов. Платить лишний рубль, выпуская миллион устройств — это выбрасывать на ветер миллион рублей, которые потребитель не оценит — они не дают ему дополнительной функциональности. Поэтому процессор сотового телефона будет расти, а процессор микроволновки — нет. Зато в какой-то момент процессор появится, наконец, в обычном телефоне, и можно будет согласовать с компом записную книжку, запрограммировать «если позвонит Маша, послать SMS, а если Галя — переводить на мобилу».

А производится маломощные чипы будут, опять-таки, долго. Они будут уменьшаться в размерах, будут продаваться партиями в 1000 (100,000) штук, но они будут по-прежнему нужны.

e2e4 писал(а):
Я писал, исходя их учебника. ‹…› Пишут - хреново. Это практика. Несколько людей думают и заботятся как написать лучше - это учебник. ‹…› Учебник, Вы считаете хуже?

Я с Вами согласен почти во всём. Я бы и раньше согласился, если бы Вы написали, скажем, «надо стремиться к тому, чтобы не смешивать new и malloc() в одном проекте», или «переопределения основных операторов, типа new, + я избегаю».

Что до учебника, то он и есть учебник, то есть концентрированный опыт, передаваемый начинающим. Во-первых, его качество зависит сильно от автора, во-вторых, у каждого из нас свой опыт. Мой слишком часто не совпадал с учебниками, которые я видел. Связано ли это с особенностями лично моего стиля, или с чем-то ещё — просто не знаю. Но отношусь к книжной мудрости скептически, привыкнув проверять её «на зуб». И слегка иронически, когда люди ссылаются на учебник, как на цитатник Мао. В программировании, мне кажется, любое утверждение учебника надо пережить самому. Не случайно расхожая характеризация информатики, как экспериментальной науки.

Есть знание, и есть умение. Знание можно почерпнуть в учебнике, умение — нет. Только своим потом.

Кроме того, мне кажется, любой приличный инженер думает, как писать лучше, обобщает свой опыт. «Кто умеет — делает, кто не умеет — учит».

 Профиль  
                  
 
 
Сообщение08.02.2008, 00:06 


21/03/06
1545
Москва
незваный гость писал(а):
Не знаю. Может быть, и проживёт долго. Мне кажется, что процессоры, память дешевеют. Одновременно с этим растёт круг задач, в которых их используют.

Дешевеют очень сильно. И круг задач растет однозначно.

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

Зачастую затраты на программный продукт больше, чем на себестоимость проц. системы.

незвный гсть писал(а):
Это, в свою очередь, приводит к тому, что пока есть предложение, ставится процессор с не более чем двухкратным запасом ресурсов.

ЫЫЫ. Двухкратным Вы сказали? :)

10-ти и 100-кратным :).
Я серьезно. Я работаю в области единичных устройств. Тут денег на процессор не считают. Зато пытаются считать деньги на мозги математика и программиста. На самом деле я могу применить в наших системах любой(ые) процессор(ы) стоимостью 1000+ баксов. Только вот алгоритмы в него заложить - это главное. К сожалению, далеко не всегда получается... Может быть поэтому я обращаюсь к учебникам, чтобы найти какой-то выход из положения... Поэтому могу себе позволить-таки юзать академичекие знания... Так получилось, я не виноват :).

Цитата:
Платить лишний рубль, выпуская миллион устройств — это выбрасывать на ветер миллион рублей, которые потребитель не оценит — они не дают ему дополнительной функциональности.

В случае массового пр-ва - совершенно верно. Да только массовые проекты в области вычислительной техники в России особо не развиваются. Кроме, может быть, сотовых компаний и их разработок. Остальное - разовое (1, 10, 100 экз.), а поэтому см. выше.

Цитата:
Поэтому процессор сотового телефона будет расти, а процессор микроволновки — нет.

Еще как проц. микроволновки будет расти. Однозначно просто скоро микроволновка подключится к инету, будет показывать погоду, рекомендовать рецепты блюд, сканировать и сопоставлять купленную мной курицу на свежесть и уплату налога на покупку :).

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

 Профиль  
                  
 
 
Сообщение08.02.2008, 06:51 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
e2e4 писал(а):
10-ти и 100-кратным Smile.
Я серьезно. Я работаю в области единичных устройств.

Конечно, Вы правы. Когда речь идёт о единичных устройствах, стоимость железа пренебрежимо мала по сравнению с затратами на программирование. Но большинство встроенных систем — именно тиражные: и телефоны, и микроволновки, и HD DVD плееры, и всё остальное. Даже системы управления (скажем, турбиной электростанции). А там нет никакого смысла тратить лишнее.

Конечно, если Вы считаете, что Китай непобедим, то думать об этом не стоит. В остальных случаях жизни…

e2e4 писал(а):
Однозначно просто скоро микроволновка подключится к инету, будет показывать погоду, рекомендовать рецепты блюд, сканировать и сопоставлять купленную мной курицу на свежесть и уплату налога на покупку

А зачем? Ужели Вы такую купите? И подключите к Интернету?

e2e4 писал(а):
то процессоры будут совершенствоваться и совершенствоваться... Память, процессорная мощность - это все будет достатчно для решения обыденных, утилитарных задач.

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

 Профиль  
                  
 
 
Сообщение09.02.2008, 12:22 


21/03/06
1545
Москва
Хух. Вернулся в Москву, могу потихоньку ответить. Извините за задержки - инет по момеду, сломалась мышка - все это не способствовало продуктивной деятельности, а заставляло пить пыво :).

незваный гость писал(а):
(1) new и delete можно переопределить не только для своих классов, но и глобально. Этим очень часто пользуются во встроенных системах, где стандартные alloc()/free() недоступны или нежелательны (представьте себе АСУ АЭС, которой не хватило памяти!).

незваный гость писал(а):
А я перепишу new. И, поверите ли, это вполне законно. Более того, для встроенных систем это применяется очень часто: 1) чтобы указать нестандартное управление распределением памяти, и 2) чтобы блокировать попытку использования стандартного.

Стоп. Самый полный стоп. Во-первых, возможно перегрузить только глобальные new и delete. Перегрузка new и delete для базовых классов невозможна. Таким образом, логически получается, что для базовых классов сначала выполняются их родные new/delete, которые в какой-то момент вызывают глобальные для выделения куска памяти, равной size_t*bytes, где bytes - аргумент глобальных new/delete. Получается вроде похоже на вызов функций malloc/free, которые также можно заменить.
Однако, насколько я понимаю (тут я не очень уверен в части конфлика имен функций, поправьте если я неправ), заменив malloc/free в стандартной библиотеке компилятора, мы навсегда меняем поведение любых программ, полученных с помощью данного компилятора, которые используют динамическое выделение памяти.
Давайте далее договоримся, что проблемы с переопределением malloc/free начинаются только тогда, когда мы не имеем доступ к части кода программы, который уже оформлен в виде скомпилированной библиотеки/объектника, и который зависим от конкретных реализаций (нестандартных) malloc/free. Таким образом, компонуя этот код с нашим открытым, мы вынуждены использовать либо навязанные нам malloc/free, либо везде применять ф-ии динамического выделения памяти с другими именами (скопировав в тело этих ф-ий например стандартные, если доступны их исходные тексты), что не всегда удобно/возможно.
Теперь вернемся к new/delete. В той же самой ситуации, глобальные переопределенные операторы new/delete обязательно находятся в объектнике скомпилированной программы. Т.е. закрытая часть кода с ними отлажена, работает, извне их код не просит - ну и хорошо. А мы в своей, открытой, части возьмем, да и не будем переопределять new/delete. И тоже прекрасно все отладим, и скомпонуем с закрытой частью. Вот тут я не уверен, будет ли конфликт имен... Но если нет - то мы получили то, что хотели - и закрытый код подключили, и стандартное поведение операторов динамического выделения памяти для базовых классов своего кода получили.

незваный гость писал(а):
Если бы нужна была только типизация, достаточно было бы написать: template <class T> T* talloc() { return (T*)malloc(sizeof(T)); }. И пользовать его в своё удовольствие: T* ptr = talloc<T>();. Вы, кстати, обратили внимание, что delete не типизированный?

Да, верно, таким образом вполне можно добиться типизации. Однако, шаблоны появились в Си++ не сразу, и даже сейчас используются не всеми.

Как это delete не типизированный? А какой же он??? :shock: delete получает в качестве аргумента указатель на конкретный экземпляр класса...

незваный гость писал(а):
Но большинство встроенных систем — именно тиражные: и телефоны, и микроволновки, и HD DVD плееры, и всё остальное. Даже системы управления (скажем, турбиной электростанции). А там нет никакого смысла тратить лишнее.

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

незваный гость писал(а):
Конечно, если Вы считаете, что Китай непобедим, то думать об этом не стоит. В остальных случаях жизни…

В ближайшие годы - непобедим, ИМХО.

незваный гость писал(а):
e2e4 писал(а):
Однозначно просто скоро микроволновка подключится к инету, будет показывать погоду, рекомендовать рецепты блюд, сканировать и сопоставлять купленную мной курицу на свежесть и уплату налога на покупку

А зачем? Ужели Вы такую купите? И подключите к Интернету?

У меня не будет особого выбора. Ненавязчиво, микроволновка не сможет обходиться без инета... Маркетологи нам это навяжут как всегда.

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

Ура, товарищи! :).

 Профиль  
                  
 
 
Сообщение09.02.2008, 13:43 
Заслуженный участник
Аватара пользователя


01/08/06
3053
Уфа
e2e4 писал(а):
У меня не будет особого выбора. Ненавязчиво, микроволновка не сможет обходиться без инета... Маркетологи нам это навяжут как всегда.

Маркетологи проведут халявный беспроводной Интернет по всей стране? Слава маркетингу! :)

e2e4 писал(а):
Ура, товарищи! :) .
Воистину ура! :D

 Профиль  
                  
 
 
Сообщение10.02.2008, 23:58 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
e2e4 писал(а):
Во-первых, возможно перегрузить только глобальные new и delete. Перегрузка new и delete для базовых классов невозможна.

Разумеется, мы можем либо переопределить операторы глобально, либо в конкретном классе.

e2e4 писал(а):
Таким образом, логически получается, что для базовых классов сначала выполняются их родные new/delete, которые в какой-то момент вызывают глобальные для выделения куска памяти, равной size_t*bytes, где bytes - аргумент глобальных new/delete.

Не понимаю. Что значит «сначала»? Почему «родные»?

e2e4 писал(а):
Однако, насколько я понимаю (тут я не очень уверен в части конфлика имен функций, поправьте если я неправ), заменив malloc/free в стандартной библиотеке компилятора, мы навсегда меняем поведение любых программ, полученных с помощью данного компилятора, которые используют динамическое выделение памяти.

Так никто же не меняет в библиотеке. Просто не нужно. Обычный подход — это заменить на свою в процессе сборки (linking). Или подставить свою библиотеку.

e2e4 писал(а):
В той же самой ситуации, глобальные переопределенные операторы new/delete обязательно находятся в объектнике скомпилированной программы.

Скорее, вызовы new/delete.

e2e4 писал(а):
и стандартное поведение операторов динамического выделения памяти для базовых классов своего кода получили.

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

e2e4 писал(а):
Как это delete не типизированный? А какой же он??? delete получает в качестве аргумента указатель на конкретный экземпляр класса...

Конечно, получает. И free() получает. Вы не видите сходства? Тогда попробуйте написать что-нибудь вроде:
Код:
class T1 {
  ~T1() {}
}

class T2: public T1 {
  ~T2() {}
}

void foo() {
  T1* p = new T2();
  delete p;
}
и угадать, какой деструктор вызовется.

 Профиль  
                  
 
 
Сообщение11.02.2008, 11:51 


21/03/06
1545
Москва
незваный гость писал(а):
e2e4 писал(а):
Таким образом, логически получается, что для базовых классов сначала выполняются их родные new/delete, которые в какой-то момент вызывают глобальные для выделения куска памяти, равной size_t*bytes, где bytes - аргумент глобальных new/delete.

Не понимаю. Что значит «сначала»? Почему «родные»?

А я и не наставиаю, что при создании, например, объекта типа int вызывается конкретно некоторая обособленная функция new для int. Однако же, компилятор перед вызовом глобального new, обязан сгенерировать код, совершающий промежуточные шаги - хотя бы положить в стек как аргумент глобального new число, соответствующее sizeof(int). Называйте эти действия "родным" new для int, или не называйте, суть остается - глобальный new подобен malloc, но перед его вызовом всегда следуют специфичные для целевого класса, типизированные действия.

незваный гость писал(а):
Так никто же не меняет в библиотеке. Просто не нужно. Обычный подход — это заменить на свою в процессе сборки (linking). Или подставить свою библиотеку.

Да это-то не суть важно.

незваный гость писал(а):
e2e4 писал(а):
В той же самой ситуации, глобальные переопределенные операторы new/delete обязательно находятся в объектнике скомпилированной программы.

Скорее, вызовы new/delete.

А вот это важно. Что, new/delete у нас находятся в какой-нибудь внешней библиотеке? Нет, они автоматически генерятся компилятором для базовых классов и непереопределенных глобальных new/delete, и запихиваются в объектник для всех пользовательских классов и переопределенных new/delete. Таким образом, объектник однозначно определяет выделение/освобождение памяти для реализованных внутри него функций и классов. Этим то new/delete существенно отличаются от malloc. Я не прав?

незваный гость писал(а):
Обеспечить определённый механизм распределения памяти для своих классов заметно проще описанием собственного механизма для них. Мне кажется, такое решение требует обоснования: обычно с бухты-барахты глобально управление памятью не меняют. А значит, меняя его локально мы создаём проблемы для программиста, использующего наш код.

Именно об этом я и пишу - я хотел бы иметь некоторое стандартное в рамках данного компилятора и ОС поведение new/delete для базовых классов. И если вдруг кто-то обоснованно или нет, поменял это поведение для своих классов, которыя я хочу использовать в своей программе, то у меня все равно остается возможность использовать стандартные new/delete. В случае с malloc это требует плясок с бубном на этапе компоновки.

незваный гость писал(а):
e2e4 писал(а):
Как это delete не типизированный? А какой же он??? delete получает в качестве аргумента указатель на конкретный экземпляр класса...

Конечно, получает. И free() получает. Вы не видите сходства? Тогда попробуйте написать что-нибудь вроде:
Код:
class T1 {
  ~T1() {}
}

class T2: public T1 {
  ~T2() {}
}

void foo() {
  T1* p = new T2();
  delete p;
}

free() получает указатель только для того, видимо, чтобы по его значению узнать, с какого адреса, и сколько (внутренние таблицы malloc?) байтов пометить как свободные.
delete же, будучи оператором языка, а не библиотечной функцией, совершенно точно знает тип, на который указывает указатель, sizeof этого типа, адрес деструктора этого типа, и действует соответственно этим знаниям. С помощью delete Вы не сможете удалить объект типа, скажем, int, как объект типа, скажем, float.
Однако, тот пример, что привели Вы, является известным узким местом языка Си++, и заключается в том, что указателю на класс-наследник можно свободно присвоить адрес класса-родителя. Этот недостаток, видимо, чем-то обусловлен, но я уже забыл, чем именно. В любом случае, такие фокусы - на совести программиста, он сознательно обошел механизм проверки типов, и флаг ему в руки тогда, компилятор удаляется.
Другой случай - с помощью явного приведения типов можно даже сделать так:
Код:
int *p = (int *)(new float);

И да, удаляться объект, на который указывает p будет как int.
Это тоже общеизвестный недостаток Си (даже Си++ уже нипричем). Вам дается свобода с приведением типов. Иногда она позволяет сделать программу более компактной и более быстрой. Опять таки, как Вы понимаете, это не проблема типизации delete.

 Профиль  
                  
 
 
Сообщение11.02.2008, 20:00 
Заслуженный участник
Аватара пользователя


17/10/05
3709
:evil:
Я подозреваю, что Вы неправильно понимаете, как именно работает компилятор. Во-первых, после первичного этапа разбора программы становится совершенно безразлично, стоял ли оператор или перегруженная функция. С этой точки зрения совершенно равноправны оператор new и функция new<T>().

Во-вторых, new, несомненно, генерируется в вызов некоторого кода. Этот код может состоять из двух вызовов (выделение памяти и конструктор) или из одного (которой вызовет и выделение памяти и конструктор). Я бы, как разработчик компилятора, предпочёл бы первый путь. Хотя бы потому, что не у всех типов есть конструкторы, а городить лишний уровень вызова — на хрен надо. Но, тем не менее, второй путь, по-видимому, законен. Передать тип параметром я, разумеется, не могу, но могу передать указатель на некоторый статический дескриптор типа.

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

В целом оператор new/delete — это мелкое мошенничество авторов языка. При описании этих операторов мы пишем только управление памятью, но при вызове происходит ещё и вызов конструкторов/деструкторов.

Поэтому, для int будет сгенерирован вызов некоторой функции operator new(size_t), по умолчанию находящейся в библиотеке. Если я определю её в своей программе (определив new), вызовется моя, а не стандартная.

e2e4 писал(а):
Что, new/delete у нас находятся в какой-нибудь внешней библиотеке? Нет

Думаю, что да. И Вы можете это легко проверить, написав тест.

e2e4 писал(а):
я хотел бы иметь некоторое стандартное в рамках данного компилятора и ОС поведение new/delete для базовых классов. И если вдруг кто-то обоснованно или нет, поменял это поведение для своих классов, которыя я хочу использовать в своей программе, то у меня все равно остается возможность использовать стандартные new/delete. В случае с malloc это требует плясок с бубном на этапе компоновки.

Я сомневаюсь, что такая возможность у Вас есть. И контексте, когда кто-то обоснованно поменял, Ваше поведение («хочу использовать стандартный») само требует обоснования. Вы уверены, что Вы этим не сломаете всю систему? Как мы уже договорились, меняли-то обоснованно.

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

e2e4 писал(а):
free() получает указатель только для того, видимо, чтобы по его значению узнать, с какого адреса, и сколько (внутренние таблицы malloc?) байтов пометить как свободные.
delete же, будучи оператором языка, а не библиотечной функцией, совершенно точно знает тип, на который указывает указатель, sizeof этого типа, адрес деструктора этого типа, и действует соответственно этим знаниям. С помощью delete Вы не сможете удалить объект типа, скажем, int, как объект типа, скажем, float.

По поводу операторности delete — см. выше. В языке нет способа передать тип параметром.

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

Не хило! Это же основа основ так называемого ООП!

Я не обхожу проверку типов. Я сознательно создаю тип-наследник, и присваиваю его указателю на тип-родитель. С ним можно делать всё, что можно с родителем. Только вот... освобождать нельзя. Потому, что delete не получает информацию о типе объекта, как Вы говорите. Он получает информацию только о типе указателя, что не одно и тоже.

А вот информацию о размере объекта он и вовсе не получает. Как и в случае с free(), она хранится в самом объекте, обычно в префиксе перед возвращаемым Вам указателем.

Более того, как только Вы сделаете деструктор виртуальным, всё заработает правильно.

 Профиль  
                  
 
 
Сообщение14.02.2008, 21:33 


21/03/06
1545
Москва
Уважаемый незваный гость!

Что я могу написать... Вы совершенно правы... Проверил в Builder'е (наиболее простой для меня способ) - компилятор действительно вызывает внешнюю, определенную в RTL, или, если компиляция происходит без RTL-библиотек, то внутреннюю, но взятую из библиотеки (видимо) функцию для выделения памяти. Честно говоря, я думал, что код, генерируемый при использовании оператора языка, вставляется компилятором автоматически, без заимствования из внешних источников. Чтож, я был не прав, признаю свои заблуждения.

Спасибо, снимаю шляпу перед Вами за столь глубокие знания и опыт!

Добавлено спустя 1 минуту 57 секунд:

Цитата:
Не хило! Это же основа основ так называемого ООП!

Я никогда не претендовал на знатока ООП :). Я знаю язык Си++ (надеюсь, достаточно глубоко, хотя бы для практика), но ни в коем случае не претендую на знание, как правильно использовать конструкции языка и концепции ООП. Более того, повторюсь, очень немногие знают, зачем все это ООП нужно.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 27 ]  На страницу Пред.  1, 2

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group