Когда читал про выделение памяти с помощью 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;
Примерно так - но только для начала :)
Комментариев нет:
Отправить комментарий