Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.09.2009, 07:23   #1
Познающий
Форумчанин
 
Аватар для Познающий
 
Регистрация: 09.05.2009
Сообщений: 162
По умолчанию Найдите ошибку. Строки. Динамич. память

Привет, друзья!!!
В который раз мучаюсь с дилемой о динамическом выделении в конструкторе и уничтожением в деструкторе. вот
Код:
void main(){
ifstream in;
ofstream out;
class S{
public:
	int i;
	char*word;
	S() {i=0; word=new char[9];}
	S(int ai,char wrd){
		i=ai;
		word=new char [wrd+1];
	}
	~S(){i=0; cout<<"DEL"; if (word)delete [] word; cout<<"END DEL";}
	S& operator [] (const int i){
		return this[i];
	}
	
};

S a[1];
a[0].i=1;
a[0].word="RED";

cout<<a[0].i<<a[0].word;
на деструкторе диагностические сообщения, так вот, стирать RED почему-то не хочет - вываливается программа, все, полный краш. Пробовал выделить массив в конструкторе по умолчанию, пробовал чуть выше тут а.вёрд=нью чар. все равно вываливается
Блин, в чем тут дело??
С наилучшими пожеланиями.

Последний раз редактировалось Sazary; 04.09.2009 в 18:20.
Познающий вне форума Ответить с цитированием
Старый 04.09.2009, 08:48   #2
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,091
По умолчанию

1. Раз уж вы работаете с классом, то уберите все члены в private секцию. i и word в public'е делать нечего.
2. В каком-то странном месте класс у вас описан, однако. Может выкинуть его из main?
3. Оператор [] у вас какой-то левый. Существует только this[0], this[1] никогда не было и не может быть. Уберите его вовсе, не нужен он вам.
4. В операторе [] параметр перекрывает член класса. Смотрите не попадите так на грабли, но это на будущее, ибо грабли там в this[i]
5. В деструкторе i = 0 - бессмысленная операция.
6. "RED" - это const char*, а word - char*. Операция a[0].word="RED"; вообще не должна работать.
7. Раз работаете с сишными строками, то читайте как их правильно копировать. см. функции: strcpy и strdup
8. Класс устроен так, что память будет течь ручьем, так что из деструктора можно смело всё удалить, разница будет не велика. В любом случае память потекёт
pu4koff на форуме Ответить с цитированием
Старый 04.09.2009, 08:54   #3
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

А у меня вопрос не скромный. А создавать a[0] инструкцией new не нужно?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 04.09.2009, 09:02   #4
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,091
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
А у меня вопрос не скромный. А создавать a[0] инструкцией new не нужно?
Неа. Тут же массив объектов, а не указателей. Для всех элементов данного массива вызовется конструктор по умолчанию.
Массив тут походу вообще для того, чтобы задействовать оператор [], но он всёравно не используется, ибо совершенно другой оператор [] перегружается
pu4koff на форуме Ответить с цитированием
Старый 04.09.2009, 09:04   #5
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
pu4koff
Ок. Ферштеен.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 04.09.2009, 10:13   #6
LaptevVV
Пользователь
 
Регистрация: 15.08.2009
Сообщений: 37
По умолчанию

Класс описан как локальный - внутри функции. На такие классы - масса ограничений (я не помню, надо смотреть в стандарте).
Надо вынести класс из функции.
LaptevVV вне форума Ответить с цитированием
Старый 04.09.2009, 15:48   #7
Познающий
Форумчанин
 
Аватар для Познающий
 
Регистрация: 09.05.2009
Сообщений: 162
По умолчанию

блин, заменил строку а(0).вёрд присвоить... на strcpy(a[0].word,"RED"); и перестало вываливаться)))
Насчет граблей всяческих то я практиковался на этом примере, хотя это уже второй раз я попался на i )))
Вот только где,блин, утечка?
С наилучшими пожеланиями.
Познающий вне форума Ответить с цитированием
Старый 04.09.2009, 17:13   #8
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

утечкой памяти в данном случае являлось присваивание переменной word нового значения, без освобождения участка памяти, на который word указывала до этого.
по поводу strcpy(a[0].word, "RED"); в данном случае так делать не надо)) Если окажется, что память, связанная с word окажется меньше копируемой строки, то вы получите AV, или что-то в этом роде. Вместо этого напишите ф-цию внутри класса, которая бы следила, чтобы память во время освобождалась и выделялась под копируемую строку, например:
Код:
void S::strcopy(char* new_str)
{
     if(strlen(word) < strlen(new_str)) {
         delete[] word;
         word = new char[strlen(new_str)+1]; // +1 для завершающего нуля
     }

     strcpy(word, new_str);
}

...
a[0].strcopy("RED");

// для большего удобства можно перегрузить оператор "=", нечто вроде:
void S::operator= (char* new_str)
{
     strcopy(new_str); // чтобы не повторять код
}
// тогда можно будет писать a[0] = "RED";
можно реализовать лучше, но это я уж думаю сами сделаете

Последний раз редактировалось netrino; 04.09.2009 в 17:18.
netrino вне форума Ответить с цитированием
Старый 04.09.2009, 17:37   #9
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,091
По умолчанию

Нигде не отлавливается изменение строки.
a[0].word = "RED" не копирует строку, а записывает в word новый указатель на строку. Вообще это компилироваться даже не должно по идее, т.к. "RED" - это константная строка.
Так вот указатель заменили, а ту память, на которую word до этого указывал, "потеряли" и не очистили.
Ну а так вываливает как раз вероятно из-за попытки удалить константную строку.
Если не касаться архитектуры класса и что он себя вообще должен представлять в вашей предметной области, я бы переписал его как минимум так:
Код:
#include <iostream>

using namespace std;

class S
{
private:
	int i_;
	char* word_;
public:
	S()
	:i_(0), word_(NULL)
	{}
	S(int ai, char const* wrd)
	:i_(ai)
	{
		word_ = NULL;
		set_word(wrd);
	}
	S(S const &obj)
	:i_(obj.i_)
	{
		word_ = NULL;
		set_word(obj.word_);
	}
	~S()
	{
		cout << "BEGIN DEL" << endl;

		if (word_)
			delete[] word_;

		cout << "END DEL" << endl;
	}
public:
	int i() const
	{
		return i_;
	}
	char const* word() const
	{
		return word_;
	}
public:
	void set_i(int new_i)
	{
		i_ = new_i;
	}
	void set_word(char const* new_word)
	{
		if (word_)
			delete[] word_;

		if (new_word)
		{
			int len = strlen(new_word);
			word_ = new char [len+1];
			strcpy(word_, new_word);
		}
		else
		{
			word_ = NULL;
		}
	}
public:
	S& operator = (S const& obj)
	{
		i_ = obj.i_;
		set_word(obj.word_);

		return *this;
	}
};

int main()
{
	cout << "1 test constructor" << endl;
	S* a = new S(1, "RED");
	S* b = new S(*a); // Вызываем конструктор копии

	cout << "a: " << a->i() << '\t' << a->word() << endl;
	cout << "b: " << b->i() << '\t' << b->word() << endl;

	delete a;
	delete b;

	cout << "2 test operator =\nbefore:" << endl;
	a = new S(2, "GREEN");
	b = new S();
	b->set_word("BLACK");

	cout << "a: " << a->i() << '\t' << a->word() << endl;
	cout << "b: " << b->i() << '\t' << b->word() << endl;

	*b = *a;

	cout << "after:" << endl;
	cout << "a: " << a->i() << '\t' << a->word() << endl;
	cout << "b: " << b->i() << '\t' << b->word() << endl;

	delete a;
	delete b;

  cin.get();
}
Корявенький конечно вариант, но мне лениво всё это "красивее" переделывать.
В моём примере проверяется корректность копирования объектов и работа оператора присваивания.
Запускаем мой код и всё работает. Так?
Заносим перегрузку оператора присваивания в комментарий и получаем сообщение об ошибке во время исполнения второго теста. В вашем классе оператор не перегружен, потому конструкция вида "a = b" скомпилируется, но приведёт к ошибке работы с памятью, т.к. одну и ту же строку второй раз в деструкторе попытаетесь удалить.
Потом комментируем конструктор копии S(S const &obj) и получаем уже ошибку в первом тесте. У вас такого конструктора так же нет, значит конструкции вида "S b(a)" и "S b = a" так же являются опасными.
В общем основные ошибки:
1) Строка выставлена наружу и её можно изменять как угодно и это может привести к чему угодно;
2) У вас POD-тип (отсутствуют реализация конструктора копии и перегрузка оператора присваивания), а таковым не может быть из-за наличия указателя.
ЗЫ. Не берите данный пример класса как пример для подражания, ибо тут и конструкторы корявенькие и в целом не ахти он, но всёже лучше исходного
pu4koff на форуме Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Найдите ошибку St1fler92 Помощь студентам 4 26.05.2009 15:23
найдите ошибку Сова Паскаль, Turbo Pascal, PascalABC.NET 9 11.02.2009 18:46
НАЙДИТЕ ОШИБКУ В ПРОГРАММЕ svetah Помощь студентам 8 03.12.2008 15:19
Найдите Ошибку. Работа с файлами Lord_Rufus Помощь студентам 2 03.10.2008 11:44
Найдите ошибку! geniy JavaScript, Ajax 4 04.12.2007 16:22