![]() |
1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!
![]() ![]() |
![]() |
TarasBer |
![]()
Сообщение
#1
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Работу с типом char* я тупо не смог осилить, так как так и не понял, при каких операциях надо выделять ему память, при каких не надо. Короче ужаснейший тип, и кто его придумал, и ну его нафиг.
Решил применить string - я так понял, что это аналог паскалевского. Но обнаружилось, что после динамического создания структуры, содержащей поле типа string, и её удаления кол-во занимаемой памяти меняется. Встатив этот кусок в бесконечный цикл, я обнаружил, что память, пожираемая программой, пульсирует от 10 до 50 MЬ. Вторая проблема - при отладке на операциях с этим типом он лезет в свои модули, мне они неинтересны, как запретить отладчику в них влазить. Блин, настроек по сравнению с Дельфой раза в 3 больше, на кой. Сообщение отредактировано: TarasBer - 18.09.2009 15:41 -------------------- |
volvo |
![]()
Сообщение
#2
|
Гость ![]() |
Цитата так и не понял, при каких операциях надо выделять ему память, при каких не надо. Выделять память надо всегда. Просто когда-то ее можно выделить самим фактом инициализации строки:char *s = "my string";, а иногда это приходится делать через new, то есть выделять память динамически. Цитата после динамического создания структуры, содержащей поле типа string, и её удаления кол-во занимаемой памяти меняется. Можно посмотреть на структуру, и на то, как выделяется память? Что говорят средства отладки (скажем, тот же CodeGuard)?Добавлено через 1 мин. Цитата Вторая проблема - при отладке на операциях с этим типом он лезет в свои модули, мне они неинтересны, как запретить отладчику в них влазить. Не делать "Step Into", а пользоваться вместо этого "Step Over", тогда отладчик будет выполнять всю строку, а не по отдельным операциям. |
TarasBer |
![]()
Сообщение
#3
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Выделять память надо всегда. Просто когда-то ее можно выделить самим фактом инициализации строки: char *s = "my string";, а иногда это приходится делать через new, то есть выделять память динамически. Но просто s = "my string" уже не катит. Что делают с памятью strcpy и strcat - тоже непонятно. Цитата Можно посмотреть на структуру, и на то, как выделяется память? Что говорят средства отладки (скажем, тот же CodeGuard)? Ну например: Код struct S { string Name; }; ... S *s; while(1){ s = new S[8]; delete s; }; Прикол в том, что если заменить string на int, то утечка полностью исчезает. В кодгуарде пока не разобрался. Цитата Добавлено через 1 мин. Не делать "Step Into", а пользоваться вместо этого "Step Over", тогда отладчик будет выполнять всю строку, а не по отдельным операциям. А если строка передаётся как параметр в функцию? Тогда степ овер пропусткает то, что делает функция, а это как раз не надо. А степ инто тут же залезает в дебри всякие. Сообщение отредактировано: TarasBer - 18.09.2009 17:51 -------------------- |
volvo |
![]()
Сообщение
#4
|
Гость ![]() |
Цитата Но просто s = "my string" уже не катит. Естественно... Для работы со строками в стиле С существуют функции, начинающиеся на str... В данном случае тебе нужен strcpy.Цитата Что делают с памятью strcpy и strcat - тоже непонятно. С чего бы? Ничего они не делают с памятью. В описании strcpy ясно написано, что "для того, чтобы избежать порчи памяти из-за переполнения, указатель destination должен указывать на область памяти достаточного объема". То есть, выделить необходимую память перед копированием - забота программиста.То же самое касается и strcat, destination должен указывать на область памяти достаточного объема, чтобы вместить результирующую строку и завершающий символ '\0'. Цитата Прикол в том, что если заменить string на int, то утечка полностью исчезает. Нет, прикол не в этом. А в том, что если ты выделяешь память под МАССИВ структур, то и удалять надо МАССИВ структур:
struct S { А почему утечка исчезает при замене string на int - это отдельный разговор, сли интересно - я расскажу, а просто так не хочется по клавишам стучать. |
TarasBer |
![]()
Сообщение
#5
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
С чего бы? Ничего они не делают с памятью. В описании strcpy ямсно написано, что "для того, чтобы избежать порчи памяти из-за переполнения, указатель destination должен указывать на область памяти достаточного объема". То есть, выделить необхпдимую память перед копированием - забота программиста. И ВСЕ стандрртные функции, возвращающие char* - тоже требуют предварительного выделения памяти? Ладно, тогда вроде понятнее. Попробую эти char* ещё раз расписать. А то что все пишут на C и не жалуются, а я не всё не врубаюсь, всё время кажется, что меня Паскаль испортил. Цитата Нет, прикол не в этом. А в том, что если ты выделяешь память под МАССИВ структур, то и удалять надо МАССИВ структур: Код ... delete [] s; } // здесь точка с запятой не нужна, кстати Вот ведь оно как, так и знал, что какую-то закорючку забыл поставить. А лишние точки с запятой, не вызывающие ошибок компиляции - разве вредят? Цитата А почему утечка исчезает при замене string на int - это отдельный разговор, сли интересно - я расскажу, а просто так не хочется по клавишам стучать. Интересно. Хотя не, такой момент ещё непонятен. Если у формы есть свойство Caption, то надо писать Caption = IntToStr(i) или сначала S = IntToStr(i), а потом Caption = S, где S - промежуточная строка, под которую выделена память? Сообщение отредактировано: TarasBer - 18.09.2009 18:48 -------------------- |
volvo |
![]()
Сообщение
#6
|
Гость ![]() |
Цитата А лишние точки с запятой, не вызывающие ошибок компиляции - разве вредят? До поры до времени - не вредят... Пока ты не напишешь какую-нибудь конструкцию, в которой эта самая точка с запятой, скажем, образует пустой цикл, пустую ветку if/else или еще что-нибудь такое же трудноуловимое. Синтаксис С очень многое позволяет "намудрить", поэтому лучше избавляться от привычки ставить лишние символы, даже если они не вызывают ошибок компиляции.Цитата Интересно. Ну, тогда смотри: при выполнении delete, если добавить [], как я сделал, происходит вот что: сначала для каждого элемента массива вызывается его деструктор, и только потом освобождается память, выделенная под сам массив. Что происходит в случае замены string на int? А ничего страшного не произойдет, даже если не вызвать деструктор для int, от него все равно толку нет, утечки не будет даже без его вызова. В случае string все серьезнее: это полноправный класс, который имеет конструктор, выделяющий память. И экземпляр этого класса требуется удалить, иначе сам экземпляр остается висеть в памяти, а указатель на него потеряется.Поэтому всегда, когда выделяешь память динамически под массив, либо состоящий из не POD-типов (Plain Old Data, данные в стиле С), либо содержащий такие типы (как у тебя - структура, которая содержит non-POD type), то освобождай ее всегда с использованием delete [] p_arr;, чтобы быть уверенным в том, что для каждого элемента вызовется деструктор, и только потом удалится сам массив. |
TarasBer |
![]()
Сообщение
#7
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Ну, тогда смотри: при выполнении delete, если добавить [], как я сделал, происходит вот что: сначала для каждого элемента массива вызывается его деструктор, и только потом освобождается память Это, я так понял, только для не-POD типов, потому что для массива объектов для каждого элемента деструктор надо вызывать руками? Решил вместо char* работать с AnsiString, а то у всех компонентов свойства как раз такого типа. -------------------- |
volvo |
![]()
Сообщение
#8
|
Гость ![]() |
Цитата Это, я так понял, только для не-POD типов, потому что для массива объектов для каждого элемента деструктор надо вызывать руками? Угу, именно поэтому...Кстати, а что за задачу ты решаешь? Может, будет выгоднее не выделять самому динамически память под массив, а воспользоваться либо vector<AnsiString> либо vector<S>? Тут ведь мало того, что не надо выделять память вручную, так еще и удалять вектор не надо, он описывается статически, следовательно при выходе из области видимости самоликвидируется (причем корректно, перед этим вызвав деструктор каждого своего элемента). |
TarasBer |
![]()
Сообщение
#9
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Кстати, а что за задачу ты решаешь? Я решаю задачу освоения нового для меня и довольно хитрого языка, за который к тому же много где платят, в отличие от Дельфей (увы, реальность примерно такова). Пока впечатление отвратительное. На примере калькулятора со встроенным парсером и ещё некоторыми наворотами (он уже знает, что 2+2*2 равно 6). Тем более, что опыт распознавания выражений имею. Собсна та структура, содержащая строчку - это описание функций, содержащее как раз и имя, и ссылку на операцию, и ещё много чего. Цитата Может, будет выгоднее не выделять самому динамически память под массив, а воспользоваться либо vector<AnsiString> либо vector<S>? Тут ведь мало того, что не надо выделять память вручную, так еще и удалять вектор не надо, он описывается статически, следовательно при выходе из области видимости самоликвидируется (причем корректно, перед этим вызвав деструктор каждого своего элемента). Ну я так понял, что фишка С++ в полной открытости всех действий перед программистом. И мне кажется, что использовать в нём подобные вещи - всё равно что покупать джип для езды по городу. -------------------- |
volvo |
![]()
Сообщение
#10
|
Гость ![]() |
Фишка С++ - не в том, чтобы не писать свой велосипед каждый раз, да еще и чинить его потом на каждом повороте, а в том, что ты берешь отлаженную сотнями и тысячами программистов библиотеку (я про STL) и просто реализуешь свою задачу. Нет, дело твое, конечно, но потом не говори, что написание программ на С++ занимает ОЧЕНЬ долгое время. Оно занимает просто долгое время, а не ОЧЕНЬ. ОЧЕНЬ - это из-за того, что ты опять с нуля реализуешь то, что уже есть в языке (хотелось бы напомнить, что STL - это часть Стандарта C++).
По поводу "джипов". Лучше я буду ездить везде на джипе, чем каждый раз менять транспортные средства (доехал до перекрестка, а там - лужа. Упс... Надо пересесть в амфибию, а то на велосипеде и утонуть можно). Хотя ко мне это относится меньше всего. Ада - язык универсальный, причем с Паскалевским синтаксисом, что снимает огромную часть проблем, да и оплачивается программирование на нем в разы (если не на порядки) выше, чем программирование на С++. И средств, подобных тому же STL-ю там не меньше, а даже больше... Так что я свой джип уже нашел. Передвигается одинаково уверенно и по Win, и по Lin, и по Embedded, и вообще практически по любым существующим территориям. Хочешь попробовать догнать? Но это уже оффтоп в данной теме. |
TarasBer |
![]()
Сообщение
#11
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Фишка С++ - не в том, чтобы не писать свой велосипед каждый раз, да еще и чинить его потом на каждом повороте, а в том, что ты берешь отлаженную сотнями и тысячами программистов библиотеку (я про STL) и просто реализуешь свою задачу. Вот как раз для такого куда лучше бы подошёл какой-нибудь другой язык, пусть не с таким оптимизированным кодом, как говорят про C++, зато более дружелюбный к программисту. А иначе зачем вообще этот C++ нужен? -------------------- |
renesko1 |
![]()
Сообщение
#12
|
![]() поиск ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 346 Пол: Мужской Реальное имя: nir Репутация: ![]() ![]() ![]() |
С++ наоборот ИМХО понятен, если программа написана с высоким и правильным содержанием STL
компонентов.(к сожалению, мои программы этим пока не очень отличаются). std::vector<car> вектор из машин) -------------------- typedef void Śūnyatā ;
|
TarasBer |
![]()
Сообщение
#13
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Хьюстон, у нас опять проблемы.
При вводе корректных выражений утечка прекратилась, но при вводе "1/0" память опять потекла. Само деление обёрнуто в
Внутри трая само деление, внутри катча присвоение пустого значения. -------------------- |
volvo |
![]()
Сообщение
#14
|
Гость ![]() |
Где память выделяется, и где она освобождается? Если сделать так:
S *s = new S[8];, то утечки не будет... Покажи, как делаешь ты... |
TarasBer |
![]()
Сообщение
#15
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Естественно, все выделения и освобождения находятся ВНЕ блока.
Чтобы указывать исключение, надо запоминать их список и названия, а операций, которые могут вызвать то или иное исключение, довольно много. Тот же логарифм, например. Проще ловить любое. Полностью блок выглядит так:
-------------------- |
volvo |
![]()
Сообщение
#16
|
Гость ![]() |
Ну, хорошо... Это переопределение операции деления. Для того, чтобы у тебя была утечка, надо, чтобы память выделялась и не освобождалась, так? Вот я и хочу увидеть, как ты вызываешь эту самую операцию деления, и что происходит в ее ближайшем окружении, после чего у тебя теряется память...
Исключение поймано, IsValue результата установлено в false, все нормально. Дальше все зависит от того, как именно ты обрабатываешь этот IsValue... |
TarasBer |
![]()
Сообщение
#17
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Значит собсна вычисление выражения выглядит так:
Тут пока так сделано, что если указатель Data.Func нулевой, то значит эта вершина содержит константу и содержимое Value и так уже правильное. Сам Data.Func, если не нулевой, ссылается на элемент из заранее созданного массива, то есть его создавать и удалять не надо. Счётчик объектов TTree говорит, что после все действий объектов ноль - то есть тут тоже всё в порядке. Operation - это указатель на тип-функцию:
Собсно сама операция, которая тут вызывается:
Тоже ничего не создаётся. -------------------- |
volvo |
![]()
Сообщение
#18
|
Гость ![]() |
Цитата Счётчик объектов TTree говорит, что после все действий объектов ноль - то есть тут тоже всё в порядке. Сомневаюсь... Поскольку сведения у меня о твоей программе только частичные - попробовал сделать так:TComplex Div(int Count, TComplex *Args) {Все нормально, утечек нет... Значит проблема-таки с TTree где-то. Подключи уже CodeGuard (у меня в Builder 2009 для этого надо установить Project -> Options -> C++ Compiler Debugging -> Enable CodeGuard в True, как это делается в BCB 6 - не помню), и посмотри, что он тебе говорит, где именно утечка? |
TarasBer |
![]()
Сообщение
#19
|
![]() Злостный любитель ![]() ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 1 755 Пол: Мужской Репутация: ![]() ![]() ![]() |
Запуск с гуардом даёт аксесс виолейшн, программа намертво виснет, не желает завершаться по команде из среды, завершается только проводником, причём так как среда об этом не узнаёт, для перекомпиляции приходится перезапускать среду.
Я не пойму, что за такая проблема с TTree может быть, которая с 1/1 не вылезает, а с 1/0 вылезает. -------------------- |
volvo |
![]()
Сообщение
#20
|
Гость ![]() |
Присоедини свой проект, я его прогоню в 2009... Можно в приват, если не хочешь выкладывать в общий доступ.
|
![]() ![]() |
![]() |
Текстовая версия | 19.06.2025 7:18 |