![]() |
Модераторы: Daevaorn |
![]() ![]() ![]() |
|
Mr_Nuke |
|
||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 101 Регистрация: 6.4.2007 Репутация: нет Всего: нет |
Собственно проблема такая.
Дана следующая программа:
---------------------------------- Суть Проблемы: Происходит суммирование, результат записывается в Z, Однако информация, находившая в X и Y потеряна. Вместо нее записаны какие то символы. Испробовано:
Почему возникает такая проблема, и какими еще способами ее можно исправить. Исходник приведен ниже [*] Заранее спасибо!
Присоединённый файл ( Кол-во скачиваний: 3 ) ![]() |
||||
|
|||||
zkv |
|
||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 26 Всего: 92 |
для начала, это неверно
правильно: s= new char [ strlen( x.s ) + strlen( y.s) ]; пардон, вернее так: s= new char [ strlen( x.s ) + strlen( y.s) + 1];
пользуетесь динамической памятью, а конструктор копирования не нарисовали
повезло просто скорее всего. Это сообщение отредактировал(а) zkv - 6.4.2007, 21:54 |
||||
|
|||||
Mr_Nuke |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 101 Регистрация: 6.4.2007 Репутация: нет Всего: нет |
я не так давно начал изучать Объектно ориентированное... не объяснишь про конструктор копирования пару сторк?
|
|||
|
||||
Damarus |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 671 Регистрация: 6.5.2006 Репутация: 6 Всего: 29 |
||||
|
||||
zkv |
|
||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 26 Всего: 92 |
при передаче в функцию объекта по значению создается копия объекта (есть еще пара таких случаев ;-)), для этого вызывается конструктор копирования, если пользователь не определил этот самый конструктор, то его создает сам компилятор. Конструктор копирования по умолчанию (вроде так он называется), просто копирует значения всех членов-данных. У тебя в этом случае копируется указатель на строку, а не сама строка, те объект в памяти остается один, а указатель на него копируется, что может привести к неприятным последствиям, если ты обратишься к этому объекту после вызова деструктора хотя бы в одном из объектов. Скорее всего не это привело к ошибке в твоей программе, там и без этого интересностей хватает ![]() Например: видимо вместо '\t' ты имел ввиду '\0'? Наверное длину строки определял? Это можно сделать функцией strlen(). Да, в твоем случае конструктор копирования должен выглядеть примерно так:
Хотя надо еще исправить этот косяк: на
Еще советую научиться нормально оформлять код (невозможно читать, место экономишь?), и выбирать более осмысленные имена идентификаторам. Ну еще неплохо сразу научить себя разделять объявление класса и реализацию его методов. Удачи! Это сообщение отредактировал(а) zkv - 6.4.2007, 22:47 |
||||
|
|||||
threef |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 375 Регистрация: 27.10.2005 Где: Запорожье Репутация: 9 Всего: 10 |
не забудь поправит деструктор
иначе будет утечка памяти. delete s; освобождает память размером с один символ |
|||
|
||||
Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
||||
|
||||
Xenon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1529 Регистрация: 12.4.2006 Репутация: 11 Всего: 50 |
Daevaorn, это просто UB без каких-либо предположений
![]() |
|||
|
||||
Mr_Nuke |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 101 Регистрация: 6.4.2007 Репутация: нет Всего: нет |
Да, определял я действительно длинну строки. Ток когда я смотрел через debug-watch, в конце строки почему то стояло '\t' На счет оформления кода - скопировал пост с сайта, где до этого размещал свою задачку.... там сайт автоматом делал вот такое вот выравнивание. Я тут первый раз, и как то не пришло в голову, что тут по другому. Поэтому и прикрепил cpp файл. и что такое UB? На счет остальных советов - буду сидеть, разбираться. Отпишусь, если будет что непонятно. Всем огромное спасибо! |
|||
|
||||
Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
||||
|
||||
Mr_Nuke |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 101 Регистрация: 6.4.2007 Репутация: нет Всего: нет |
И еще один вопросик. Что делает "const"?
Чем отличается "str(char *st)" от "str( const char *st )" ? |
|||
|
||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 13 Всего: 56 |
оно делает как раз то, что это слово означает ![]() |
|||
|
||||
bsa |
|
||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 63 Всего: 196 |
Это больше касается качества кода. Т.е. объявляя функцию с константным указателем или ссылкой в качестве параметра, ты гарантируешь всем, кто ее использует (а так же компилятору, который компилирует твой код), что ты не изменяешь переменную, на которую указывает указатель или ссылка. Другими словами, если ты по ошибке напишешь это:
Больше того, у методов классов тоже есть модификатор const, который означает, что данный метод не меняет аттрибуты класса. По мимо всего прочего, данные модификаторы помогают при написании программы. Например, ты пишешь класс, у которого есть метод size():
|
||||||||
|
|||||||||
Mr_Nuke |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 101 Регистрация: 6.4.2007 Репутация: нет Всего: нет |
Все супер! все работает!
![]() остался последний вопрос: про конструктор копирования.
первая строчка "&obStr". все слово является какой то переменной или str - это имя класса? если так, то почему оно с большой буквы? Или это указатель на копируемый объект? |
|||
|
||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 26 Всего: 92 |
obStr - это идентификатор (типа object класса str) знак & - указывает, что объект передается по ссылке. По значению объект в конструктор копирования не передать, так как для этого надо вызвать конструктор копирования ![]() ну так захотелось ![]() |
|||
|
||||
Mr_Nuke |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 101 Регистрация: 6.4.2007 Репутация: нет Всего: нет |
на счет конструктора разобрался!
![]() Везде, где мы выделяем память, мы выделяем на 1 байт(или бит), тоесть дописываем +1 к необходимой длинне; как нас учили, это делается для того, что бы руками потом дописывать "\0", показывая конец строки. но мы этого не делаем. Первый вопрос: почему тогда информация сохраняется верной? ведь мы выделили память на 1 байт больше, чем записали, т.е. один байт остается свободным. почему туда не записывается какой либо мусор? и если мы всеравно ничего не дописываем, почему мы не можем не выделять на один байт больше? т.е. не выделять этот лишний байт. Если не писать +1, то в конструкторе копирования, в нужную нам строчку дописывается какой то символ в конце. Так куда он пишется, если мы не выделяли место под этот символ? Это сообщение отредактировал(а) Mr_Nuke - 8.4.2007, 19:39 |
|||
|
||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 26 Всего: 92 |
||||
|
||||
Mr_Nuke |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 101 Регистрация: 6.4.2007 Репутация: нет Всего: нет |
Всё! всем огромное спасибо!
![]() ![]() zkv и bsa! вам отдельное спасибо! если бы мог - влепил бы вам по плюсику в репутацию) но пока у меня постов маловато ![]() |
|||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
Нет, освобождает ровно столько, сколько по адресу s выделено. Другое дело, что деструктор вызывается только для одного объекта (первого символа), и именно этим отличается от delete[] s - последний вызовет деструктор для каждого символа. Но в данном случае это не существенно - это же просто символы. Не надо быть святее папы Римского ![]() Добавлено через 3 минуты и 6 секунд И никакое это не UB, а вполне стандартное поведение -------------------- ... |
|||
|
||||
Xenon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1529 Регистрация: 12.4.2006 Репутация: 11 Всего: 50 |
||||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
Xenon, у меня по твоей ссылке пустая страница открывается...
Но тем не менее, что тут может быть UB - удалится весь выделенный блок или нет? -------------------- ... |
|||
|
||||
Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
||||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
Вот, вроде нашла, что ты имел ввиду, Xenon:
Оно? Только здесь написано, что UB, если вызвать delete для array object pointer. И еще про "If the operand has a class type". Конечно UB - память удалится, а часть объектов не разрушится - в зависимости от объектов может случиться что угодно. Так будет, если удалить без [] массив, скажем string... Только простые символы (и вообще встроенные типы) так рассматривать не стоит... Ну сам подумай, какое UB тут может быть? -------------------- ... |
|||
|
||||
Daevaorn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2155 Регистрация: 29.11.2004 Где: Москва Репутация: 51 Всего: 70 |
||||
|
||||
Xenon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1529 Регистрация: 12.4.2006 Репутация: 11 Всего: 50 |
Теперь, думаю, сомнений нет?
![]()
Это сообщение отредактировал(а) Xenon - 9.4.2007, 20:58 |
|||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
Ну да, да, это аргумент, действительно...
Я, конечно, имела в виду встроенные операторы, а не переопределенные. Только я сразу пристрелю программиста в моей группе, если он вздумает переопределить delete и delete[] несовместимо. Да и вообще переопределить delete для встроенных типов. Ей-богу, вреда от каких переопределений в долгосрочной перспективе гораздо больше чем пользы. Если уж приспичило выделять память для интов через ж. коленом, так делать это нужно явно, шоб ясно было видно: MySuperCrazyIntAlloc() \ MySuperCrazyIntFree() ! Но формально ты прав. -------------------- ... |
|||
|
||||
JackYF |
|
|||
![]() полуавантюрист ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 5814 Регистрация: 28.8.2004 Где: страна тысячи озё р Репутация: 18 Всего: 162 |
Мне тут скоро писать лабу-курсак... Там как раз надо хоть раз выделить память собственным аллокатором... Я все думал, как назвать ![]() оффтоп, конечно. зачем же так сразу... может, он решит пошутить ![]() |
|||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
![]() Это будет гуманитарная акция... Потому что после того, как другие программисты, промаявшись с экзотическим поведением совершенно нормально выглядящего кода, обнаружат причину, его смерть будет долгой и мучительной... ![]() ![]() ![]() -------------------- ... |
|||
|
||||
![]() ![]() ![]() |
Правила форума "С++:Общие вопросы" | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |