Страницы

Поиск по вопросам

вторник, 23 апреля 2019 г.

Освобождение памяти в структуре

Когда читал про выделение памяти с помощью new и ее освобождения, возник вопрос. Вот пример кода:
const int size_m = 40;
int main () { struct car { char *name; };
int QCar; cout << "How many car?"; cin >> QCar; car *pCar = new car[QCar]; for ( int i = 0; i < QCar; i++) { cout << "Car name: "; char temp [size_m]; char >> temp; char *ptemp = new char [strlen(temp)+1]; strcpy(ptemp,temp); pCar[i].name = ptemp; } cout << " Your auto"<< endl; for ( int i = 0; i < QCar; i++) { cout << pCar[i].name; } delete []pCar; system("pause"); return 0; }
Является ли достаточным только это освобождение или нужно еще. Или вообще иначе. Просто выделение памяти дважды , а удаление одно.


Ответ

Почти правильно :) Сейчас поясню, почему "почти".
В C++ у каждого объекта есть такая вешь, как конструктор и деструктор. Если их не написать самому - их сгенерирует компилятор (все несколько сложнее, но я упрощаю как только могу). Деструктор вызывается при уничтожении объекта, так что вот тут
delete []pCar;
он будет вызван. Но вы не написали свой деструктор, а генерируемый понятия не имеет, что делать с name и потому не делает ничего. Так что надо дописать свой деструктор -
struct car { char *name; ~car() { delete[]name; } };
В таком случае будет достаточно написать ваш delete []pCar; - и все будет корректно. Почти. Почему почти? потому что а вдруг вы забудете инициализировать name? И он будет показывать непонятно куда, а при удалении непонятно чего произойти может все, что угодно. Поэтому давайте допишем конструктор
car(): name(nullptr) {}
И все бы ничего, но ведь кто-то может (может, даже вы) написать где-то pCar->name = "ПЦ". И при попытке освобождения будут неприятности. Поэтому лучше делать не структуру, а класс:
struct car { public: car(): name(nullptr) {} ~car() { delete[]name; } private: char *name; };
Готово? Почти. Потому что надо еще как-то теперь заставить name хранить строку. Опять же, делаем конструктор
car(const char * str):name(nullptr) { if (str) { name = new char[strlen(str)+1]; strcpy(name,str); } }
и функцию-член для обращения к этой строке:
const char* str() const { return name; }
и оператор присваивания, чтоб name менять:
car& operator=(const char * str) { delete[]name; if (str) { name = new char[strlen(str)+1]; strcpy(name,str); } else name = nullptr; }
Вот теперь можно считать готово. Можно дописать еще многое, но главное - уже на месте:
struct car { public: car(const char * str = nullptr):name(nullptr) { if (str) { name = new char[strlen(str)+1]; strcpy(name,str); } } ~car() { delete[]name; } const char str() const { return name; } car& operator=(const char * str) { delete[]name; if (str) { name = new char[strlen(str)+1]; strcpy(name,str); } else name = nullptr; } private: char *name; };
А ваш код превращается в
car *pCar = new car[QCar]; for ( int i = 0; i < QCar; i++) { cout << "Car name: "; char temp [size_m]; char >> temp; pCar[i] = temp; } cout << " Your auto"<< endl; for ( int i = 0; i < QCar; i++) { cout << pCar[i].str(); } delete []pCar;
Примерно так - но только для начала :)

Комментариев нет:

Отправить комментарий