Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Листинг 9.14. Утечка памяти
1: // Листинг 9.14. 2: // Разрешение проблемы утечки памяти 3: #include < iostream.h> 4: 5: class SimpleCat 6: { 7: public: 8: SimpleCat (int age, int weight); 9: ~SimpleCat() { } 10: int GetAge() { return itsAge; } 11: int GetWeight() { return itsWeight; } 12: 13: private: 14: int itsAge; 15: int itsWeight; 16: }; 17: 18: SimpleCat:: SimpleCat(int age, int weight) 19: { 20: itsAge = age; 21: itsWeight = weight; 22: } 23: 24: SimpleCat & TheFunction(); 25: 26: int main() 27: { 28: SimpleCat & rCat = TheFunction(); 29: int age = rCat.GetAge(); 30: cout < < " rCat " < < age < < " years old! \n"; 31: cout < < " & rCat: " < < & rCat < < endl; 32: // Как освободить эту память? 33: SimpleCat * pCat = & rCat; 34: delete pCat; 35: // Боже, на что же теперь ссылается rCat?? 36: return 0; 37: } 38: 39: SimpleCat & TheFunction() 40: { 41: SimpleCat * pFrisky = new SimpleCat(5, 9); 42: cout < < " pFrisky: " < < pFrisky < < endl; 43: return *pFrisky; 44: }
Результат: pFrisky: 0x00431C60 rCat 5 years old! & rCat: 0x00431C60
Предупреждение: Эта программа компилируется, компонуется и, кажется, работает. Но мина замедленного действия уже ожидает своего часа.
Анализ: Функция TheFunction() была изменена таким образом, чтобы больше не возвращать ссыпку на локальную переменную. В строке 41 вычисляется некоторая область динамически распределяемой памяти и ее адрес присваивается указателю. Этот адрес выводится на экран, после чего указатель разыменовывается и объект класса SimpleCat возвращается по ссылке. В строке 28 значение возврата функции TheFunction() присваивается ссылке на объект класса SimpleCat, а затем этот объект используется для получения возраста кота, и полученное значение возраста выводится на экран в строке 30. Чтобы доказать, что ссылка, объявленная в функции main(), ссылается на объект, размещенный в области динамической памяти, выделенной для него в теле функции TheFunction(), к ссылке rCat применяется оператор адреса (&). Вполне убедителен тот факт, что адрес объекта, на который ссылается rCat, совпадает с адресом объекта, расположенного в свободной области памяти. До сих пор все было гладко. Но как же теперь освободить эту область памяти, которая больше не нужна? Ведь нельзя же выполнять операции удаления на ссылках. На ум приходит одно решение: создать указатель и инициализировать его адресом, полученным из ссылки rCat. При этом и память будет освобождена, и условия для утечки памяти будут ликвидированы. Все же одна маленькая проблема остается: на что теперь ссылается переменная rCat после выполнения строки 34? Как указывалось выше, ссылка всегда должна оставаться псевдонимом реального объекта; если же она ссылается на нулевой объект (как в данном случае), о корректности программы говорить нельзя.
Примечание: Не будет преувеличением определение программы как некорректной, если она содержит ссылку на нулевой объект (несмотря на то что она успешно компилируется), поскольку результаты ее выполнения непредсказуемы.
Для решения этой проблемы есть три пути. Первый состоит в объявлении объекта класса SimpleCat в строке 28 и возвращении этого объекта из функции TheFunction как значения. Второй — в объявлении класса SimpleCat в свободной области (в теле функции TheFunction()), но сделать это нужно так, чтобы функция TheFunction() возвращала указатель на данный объект. Затем, когда объект больше не нужен, его можно удалить в вызывающей функции с помощью оператора delete. Третье решение (возможно, самое правильное) — объявить объект в вызывающей функции, а затем передать в функцию TheFunction() ссылку на него.
|