class CStr {
public:
CStr(char * str) {
if(!str) {
m_Ch = new char[1];
*m_Ch = 0x0;
}
else {
m_Ch = new char[strlen(str)+1];
strcpy(m_Ch,str);
}
}
~CStr() { delete(m_Ch); }
void dump(std::ostream & strm) {
strm << "\"" << m_Ch << "\"\n";
}
private:
char * m_Ch;
};
CStr * s1 = new CStr("First String !!!");
CStr * s2 = new CStr("Second String !!!");
s1->dump(std::cout);
s2->dump(std::cout);
s2 = s1;
s1->dump(std::cout);
s2->dump(std::cout);
delete(s1);
s2->dump(std::cout);
delete(s2);
Думаю этот пример убедил, что нужно быть внимательней при разработке класса ;)
4 комментария:
Я не уловил феномена. Не могу понять, то ли из-за не знания тонкостей, то ли наоборот. =)
~CStr() { delete(m_Ch); }
Распространённая ошибка - с массивами надо использовать delete []. Из C++ Faq Lite:
[16.12] What if I forget the [] when deleteing array allocated via new T[n]?
All life comes to a catastrophic end.
It is the programmer's —not the compiler's— responsibility to get the connection between new T[n] and delete[] p correct. If you get it wrong, neither a compile-time nor a run-time error message will be generated by the compiler. Heap corruption is a likely result. Or worse. Your program will probably die.
2 Hunt :
Тонкость заключена в том, что в классе CStr не перегружен оператор присваивания и следовательно используется тот оператор '=', который по дефолту! ;)
s2 = s1;
Тут всё-таки копирование указателя на объект. В s2 и s1 после этой строки хранится один и тот же адрес:
printf("0x%p, 0x%p\n", s1, s2);
Конструктор копирования вызвался бы в этом случае:
*s2 = *s1;
1) Создание двух объектов класса строк
2) s2 = s1; тут вызывается оператор присвания по умолчанию, а не конструктор! А он в свою очередь копирует указатель на первую строку!!!
3) Херится, т.е. утечка памяти , т.к. уже ни кто не указывает на вторую строку
4) Первый объект удаляется, но второй продолжает указывать на ту область где раньше лежала первая строка
5) пытаемся юзать dump
6) пытаемся удалить второй объект
Это разве хорошо? ;)
Отправить комментарий