Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Неправильная работа деструктора |
Автор: Mr_Nuke 6.4.2007, 21:38 | ||||
Собственно проблема такая. Дана следующая программа:
---------------------------------- Суть Проблемы: Происходит суммирование, результат записывается в Z, Однако информация, находившая в X и Y потеряна. Вместо нее записаны какие то символы. Испробовано:
Почему возникает такая проблема, и какими еще способами ее можно исправить. Исходник приведен ниже [*] Заранее спасибо!
|
Автор: zkv 6.4.2007, 21:43 | ||||
для начала, это неверно правильно: s= new char [ strlen( x.s ) + strlen( y.s) ]; пардон, вернее так: s= new char [ strlen( x.s ) + strlen( y.s) + 1];
пользуетесь динамической памятью, а конструктор копирования не нарисовали
повезло просто скорее всего. |
Автор: Mr_Nuke 6.4.2007, 22:14 |
я не так давно начал изучать Объектно ориентированное... не объяснишь про конструктор копирования пару сторк? |
Автор: Damarus 6.4.2007, 22:40 |
sizeof(st) обычно будет 4. |
Автор: zkv 6.4.2007, 22:45 | ||||
при передаче в функцию объекта по значению создается копия объекта (есть еще пара таких случаев ;-)), для этого вызывается конструктор копирования, если пользователь не определил этот самый конструктор, то его создает сам компилятор. Конструктор копирования по умолчанию (вроде так он называется), просто копирует значения всех членов-данных. У тебя в этом случае копируется указатель на строку, а не сама строка, те объект в памяти остается один, а указатель на него копируется, что может привести к неприятным последствиям, если ты обратишься к этому объекту после вызова деструктора хотя бы в одном из объектов. Скорее всего не это привело к ошибке в твоей программе, там и без этого интересностей хватает ![]() Например: видимо вместо '\t' ты имел ввиду '\0'? Наверное длину строки определял? Это можно сделать функцией strlen(). Да, в твоем случае конструктор копирования должен выглядеть примерно так:
Хотя надо еще исправить этот косяк: на
Еще советую научиться нормально оформлять код (невозможно читать, место экономишь?), и выбирать более осмысленные имена идентификаторам. Ну еще неплохо сразу научить себя разделять объявление класса и реализацию его методов. Удачи! |
Автор: threef 7.4.2007, 00:24 | ||
не забудь поправит деструктор
иначе будет утечка памяти. delete s; освобождает память размером с один символ |
Автор: Daevaorn 7.4.2007, 01:25 |
не хочу быть особо въедливым, но это совсем не факт. в большинстве случаев удалится всё-таки вся память, а вот с вызовом деструкторов будут проблемы. а вообще это UB |
Автор: Xenon 7.4.2007, 01:37 |
Daevaorn, это просто UB без каких-либо предположений ![]() |
Автор: Mr_Nuke 7.4.2007, 10:09 | ||
Да, определял я действительно длинну строки. Ток когда я смотрел через debug-watch, в конце строки почему то стояло '\t' На счет оформления кода - скопировал пост с сайта, где до этого размещал свою задачку.... там сайт автоматом делал вот такое вот выравнивание. Я тут первый раз, и как то не пришло в голову, что тут по другому. Поэтому и прикрепил cpp файл. и что такое UB? На счет остальных советов - буду сидеть, разбираться. Отпишусь, если будет что непонятно. Всем огромное спасибо! |
Автор: Daevaorn 7.4.2007, 10:17 |
http://en.wikipedia.org/wiki/Undefined_behavior |
Автор: Mr_Nuke 7.4.2007, 16:55 |
И еще один вопросик. Что делает "const"? Чем отличается "str(char *st)" от "str( const char *st )" ? |
Автор: vinter 7.4.2007, 20:13 |
оно делает как раз то, что это слово означает ![]() |
Автор: bsa 7.4.2007, 21:28 | ||||||||
Это больше касается качества кода. Т.е. объявляя функцию с константным указателем или ссылкой в качестве параметра, ты гарантируешь всем, кто ее использует (а так же компилятору, который компилирует твой код), что ты не изменяешь переменную, на которую указывает указатель или ссылка. Другими словами, если ты по ошибке напишешь это:
Больше того, у методов классов тоже есть модификатор const, который означает, что данный метод не меняет аттрибуты класса. По мимо всего прочего, данные модификаторы помогают при написании программы. Например, ты пишешь класс, у которого есть метод size():
|
Автор: Mr_Nuke 8.4.2007, 19:11 | ||
Все супер! все работает! ![]() остался последний вопрос: про конструктор копирования.
первая строчка "&obStr". все слово является какой то переменной или str - это имя класса? если так, то почему оно с большой буквы? Или это указатель на копируемый объект? |
Автор: Mr_Nuke 8.4.2007, 19:36 |
на счет конструктора разобрался! ![]() Везде, где мы выделяем память, мы выделяем на 1 байт(или бит), тоесть дописываем +1 к необходимой длинне; как нас учили, это делается для того, что бы руками потом дописывать "\0", показывая конец строки. но мы этого не делаем. Первый вопрос: почему тогда информация сохраняется верной? ведь мы выделили память на 1 байт больше, чем записали, т.е. один байт остается свободным. почему туда не записывается какой либо мусор? и если мы всеравно ничего не дописываем, почему мы не можем не выделять на один байт больше? т.е. не выделять этот лишний байт. Если не писать +1, то в конструкторе копирования, в нужную нам строчку дописывается какой то символ в конце. Так куда он пишется, если мы не выделяли место под этот символ? |
Автор: zkv 8.4.2007, 19:44 | ||
кто сказал что мы ничего туда не записываем? В следующем примере это сделает функция strcpy().
Остальные вопросы снимаются, как я понимаю ![]() |
Автор: Mr_Nuke 8.4.2007, 19:52 |
Всё! всем огромное спасибо! ![]() ![]() zkv и bsa! вам отдельное спасибо! если бы мог - влепил бы вам по плюсику в репутацию) но пока у меня постов маловато ![]() |
Автор: Earnest 9.4.2007, 20:10 | ||
Нет, освобождает ровно столько, сколько по адресу s выделено. Другое дело, что деструктор вызывается только для одного объекта (первого символа), и именно этим отличается от delete[] s - последний вызовет деструктор для каждого символа. Но в данном случае это не существенно - это же просто символы. Не надо быть святее папы Римского ![]() Добавлено через 3 минуты и 6 секунд И никакое это не UB, а вполне стандартное поведение |
Автор: Xenon 9.4.2007, 20:20 |
Earnest, это UB. http://rsdn.ru/Forum/Info.aspx?name=FAQ.cpp.delete[] |
Автор: Earnest 9.4.2007, 20:25 |
Xenon, у меня по твоей ссылке пустая страница открывается... Но тем не менее, что тут может быть UB - удалится весь выделенный блок или нет? |
Автор: Daevaorn 9.4.2007, 20:29 | ||
там последнии [] - часть ссылки
всё |
Автор: Earnest 9.4.2007, 20:50 | ||
Вот, вроде нашла, что ты имел ввиду, Xenon:
Оно? Только здесь написано, что UB, если вызвать delete для array object pointer. И еще про "If the operand has a class type". Конечно UB - память удалится, а часть объектов не разрушится - в зависимости от объектов может случиться что угодно. Так будет, если удалить без [] массив, скажем string... Только простые символы (и вообще встроенные типы) так рассматривать не стоит... Ну сам подумай, какое UB тут может быть? |
Автор: Daevaorn 9.4.2007, 20:52 |
ну допустим у меня на микроконтролере память под массивы отдельно от остальной для оптимизации. |
Автор: Xenon 9.4.2007, 20:56 | ||
Теперь, думаю, сомнений нет? ![]()
|
Автор: Earnest 9.4.2007, 21:05 |
Ну да, да, это аргумент, действительно... Я, конечно, имела в виду встроенные операторы, а не переопределенные. Только я сразу пристрелю программиста в моей группе, если он вздумает переопределить delete и delete[] несовместимо. Да и вообще переопределить delete для встроенных типов. Ей-богу, вреда от каких переопределений в долгосрочной перспективе гораздо больше чем пользы. Если уж приспичило выделять память для интов через ж. коленом, так делать это нужно явно, шоб ясно было видно: MySuperCrazyIntAlloc() \ MySuperCrazyIntFree() ! Но формально ты прав. |
Автор: JackYF 10.4.2007, 01:02 |
Мне тут скоро писать лабу-курсак... Там как раз надо хоть раз выделить память собственным аллокатором... Я все думал, как назвать ![]() оффтоп, конечно. зачем же так сразу... может, он решит пошутить ![]() |
Автор: Earnest 10.4.2007, 07:43 |
![]() Это будет гуманитарная акция... Потому что после того, как другие программисты, промаявшись с экзотическим поведением совершенно нормально выглядящего кода, обнаружат причину, его смерть будет долгой и мучительной... ![]() ![]() ![]() |