Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Строковый класс, Помогите в освоении языка :) 
:(
    Опции темы
NightGoblin
Дата 20.12.2002, 17:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1021
Регистрация: 24.11.2002
Где: 127.0.0.1

Репутация: нет
Всего: 11



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

Ситуация такова: есть строковый класс rstring (распространенный учебный пример для начинающих), содержащий два приватных элемента: char* (без нуль-терминатора) и unsigned int, описывающий его длину. При нем определены операторы сравнения, присвоения и конкатенации. В последних и есть проблема. Есть простая тестовая программка, где объявляются три объекта этого класса: два содержат разные строки, третий служит для получения результата конкатенации. Вроде бы все работает, но не работает: после распечатки сообщения, при завершении выдает Segmentation fault. Вроде понятно, что должна быть ошибка с выделением/освобождением памяти, но вот где точно - не знаю. Удалось выяснить, что проблема в операторе "+" (скорее всего), поскольку без него все работает нормально. Вот исходный код оператора:
Код

rstring operator+ (rstring a, rstring b)
{
   char *ts, *p, *ad, *bd;
   int i, al, bl;

   al = a.getlength ();
   bl = b.getlength ();
   ad = a.getptr ();
   bd = b.getptr ();

   ts = new char [al + bl + 1];
   p = ts;

   for (i = 0; i < al; i++)
       *p++ = ad[i];

   for (i = 0; i < bl; i++)
       *p++ = bd[i];

   *p = 0;

   rstring str = ts;
   delete [] ts;

   return str;
}

Кстати, аналогичный opertator+ (rstring, char*) вообще возвращает пустую строку... Не подскажете, в чем может быть проблема?


--------------------
Kernel panic: /dev/null overflow!
GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y?
B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981
PM MAIL WWW ICQ   Вверх
Baa
Дата 20.12.2002, 19:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2639
Регистрация: 12.4.2002
Где: Москва

Репутация: 8
Всего: 12



В глаза сразу это бросилось, в остальной код я не вглядывался...
Код

rstring str = ts;
  delete [] ts;

  return str;

Тут к str присваивается указатель ts, а потом мы удаляем все, на что этот указатель указывал.
И в результате возвращаем нечто...




--------------------
"Duty is everything; the greatest of joys, the deepest of sorrows" Aribeth de Tylmarande
PM ICQ   Вверх
Step
Дата 20.12.2002, 19:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5151
Регистрация: 26.9.2002
Где: дурдом.UA

Репутация: 5
Всего: 25



Цитата(Baa @ 20.12.2002, 11:02)
Тут к str присваивается указатель ts, а потом мы удаляем все, на что этот указатель указывал.
И в результате возвращаем нечто...

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


--------------------
- Дурак учится на своих ошибках, умный на чужих.
 - умные учатся у дураков
PM MAIL ICQ   Вверх
Baa
Дата 20.12.2002, 23:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2639
Регистрация: 12.4.2002
Где: Москва

Репутация: 8
Всего: 12



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


--------------------
"Duty is everything; the greatest of joys, the deepest of sorrows" Aribeth de Tylmarande
PM ICQ   Вверх
Step
Дата 21.12.2002, 00:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5151
Регистрация: 26.9.2002
Где: дурдом.UA

Репутация: 5
Всего: 25



Цитата(Baa @ 20.12.2002, 15:02)
На самом деле, возврат указателя - штука очень удобная... но вот надо быть полностью увереным в добросовестности других функций, дабы они за собой почистили память.

Это конецно интересно, только вот возникает проблема когда два раза подряд эту функцию вызываеш.


--------------------
- Дурак учится на своих ошибках, умный на чужих.
 - умные учатся у дураков
PM MAIL ICQ   Вверх
Fantasist
Дата 21.12.2002, 02:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: 4
Всего: 41



Цитата(Baa @ 20.12.2002, 11:02)
Код

rstring str = ts;
  delete [] ts;

  return str;

Тут к str присваивается указатель ts, а потом мы удаляем все, на что этот указатель указывал.
И в результате возвращаем нечто...

Смотри внимательнее. Переменныя str имеет тип rstring, а значит тут будет вызван конструктор rstring([const] char*), который скорее всего произведет копирование.

Вообще, на первый взгляд ошибок не видно. Походи деббагером - все проявиться.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
Fantasist
Дата 21.12.2002, 03:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: 4
Всего: 41



Цитата(NightGoblin @ 20.12.2002, 09:31)
...

Вообще-то по-моему, лучше реализовать это примерно так:

Код

void shstrcpy(char* source,const char*& dest,int count);
{
 for (int i=0; i<count; ++i)
    *source++=*dest++;
}

rstring operator+ (rstring a, rstring b)
{
   rstring new_str;
   new_str.SetLenght(a.getlength ()+b.getlength ());
   
   char* p=new_str.getbuffer();
   shstrcpy(a.getbuffer(),p,a.getlength());
   shstrcpy(b.getbuffer(),p,b.getlength());

   return new_str;
}

Понятнее и эффективнее. Можно, конечно, еще лучше, но это уже надо класс редактировать. getbuffer() должна возвращать внутренний указатель на char* и возможно следует сделать ее приватной. Функции getbuffer() и getlenght() (а можно и SetLenght()) нужно сделать inline.

Да! Совсем забыл. Убедись, что у тебя правильно определен конструктор копий.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
dim
Дата 21.12.2002, 04:39 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Еще вылетать может быть если либо не инициализируется член содержащий длину или же он не меняется при изменении члена содержащего собсвенно строку, например в том же констукторе копирования. Вообщем все места в классе с ним связанные лучше проверить.
  Вверх
DrMasik
Дата 21.12.2002, 07:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 13.12.2002

Репутация: нет
Всего: нет



1. rstring str = ts;//Посмотри внимательно!!!!
2.   delete [] ts;
3. return str;

В строке 1, ты присваиваешь переменной "занчение" которое содержится в ts!
таким образом, если ты вызываешь после строки 2, что ты и сделал в строке 3, то ты обращаешся туда. чего уже нет!
:colgate
PM MAIL ICQ   Вверх
NightGoblin
Дата 21.12.2002, 17:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1021
Регистрация: 24.11.2002
Где: 127.0.0.1

Репутация: нет
Всего: 11



Цитата(DrMasik @ 20.12.2002, 23:49)
1. rstring str = ts;//Посмотри внимательно!!!!
2.   delete [] ts;
3. return str;

В строке 1, ты присваиваешь переменной "занчение" которое содержится в ts!
таким образом, если ты вызываешь после строки 2, что ты и сделал в строке 3, то ты обращаешся туда. чего уже нет!
:colgate

(а также 2 Baa)

Да, прошу прощения, забыл сказать, что конструктор rstring (const char*) для rstring действительно определен так, что char* копируется в rstring, а не просто указатель на него присваивается массиву char в rstring. Иначе бы вообще не работало...


--------------------
Kernel panic: /dev/null overflow!
GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y?
B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981
PM MAIL WWW ICQ   Вверх
NightGoblin
Дата 21.12.2002, 17:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1021
Регистрация: 24.11.2002
Где: 127.0.0.1

Репутация: нет
Всего: 11



Цитата(Fantasist @ 20.12.2002, 19:05)
Вообще-то по-моему, лучше реализовать это примерно так:
...

Хм, спасибо, надо попробовать :)


--------------------
Kernel panic: /dev/null overflow!
GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y?
B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981
PM MAIL WWW ICQ   Вверх
NightGoblin
Дата 21.12.2002, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1021
Регистрация: 24.11.2002
Где: 127.0.0.1

Репутация: нет
Всего: 11



2Fantasist:

Короче, говоря, спасибо за улучшенную реализацию. Однако, при переделке обнаружилась некая странная вещь: проблема вроде как даже и не в "+": если это выражение поставить в конструктор (rstring c = a + b;), то все работает без всяких Segmentation fault'ов, даже со старой функцией оператора. С другой стороны, если написать просто c = a, все выполнится опять же гладко. И только когда объекту присваивается результат конкатенации, начинаются чудеса... В общем, будем копать :)


--------------------
Kernel panic: /dev/null overflow!
GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y?
B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981
PM MAIL WWW ICQ   Вверх
NightGoblin
  Дата 21.12.2002, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1021
Регистрация: 24.11.2002
Где: 127.0.0.1

Репутация: нет
Всего: 11



Прошу прощения за флуд. ))

Проблема выяснена: стоило в операторе присваивания (rstring::operator=) поставить аргументом rstring вместо rstring*, все заработало как надо :) Всем  огромное спасибо за помощь :inlove

ну и программер из меня однако :withstupid :laugh


--------------------
Kernel panic: /dev/null overflow!
GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y?
B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981
PM MAIL WWW ICQ   Вверх
Fantasist
Дата 22.12.2002, 04:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: 4
Всего: 41



Цитата(NightGoblin @ 21.12.2002, 10:40)
Однако, при переделке обнаружилась некая странная вещь: проблема вроде как даже и не в "+":

А это с самого начало было понятно.  :p
Я же сказал, что в том коде ошибок не видно, и предлагал дебаггером походить.


--------------------
Волны гасят ветер...
PM MAIL   Вверх
NightGoblin
Дата 22.12.2002, 18:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1021
Регистрация: 24.11.2002
Где: 127.0.0.1

Репутация: нет
Всего: 11



Кстати, при передаче аргументов rstring& rstring::operator= (rstring); в виде rstring, а не rstring* использует указатели или так и пихает всю структуру в стек?...


--------------------
Kernel panic: /dev/null overflow!
GCS/IT/MU/O d-@ s: a- C++$>++++$ ULSB(+++) P+++ L+++>++++ !E W++(-) N o? K w-- O? M>+ V? PS+ PE Y+ PGP+>+++ t- 5 X+ R- !tv b+ DI+ D+ G e++ h--- r++ y?
B4F1 54B6 8738 26CD 5125 0581 B923 9273 FE59 1981
PM MAIL WWW ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0774 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.