Професионална програма
Loading...
+ Нов въпрос
Hristo_Penchev avatar Hristo_Penchev 389 Точки

C++ презаписване на деструктори - продължава ли да зачиства паметта?

Здравейте,

Опитвам се да разбера как работят деструкторите и какво се случва, когато ги презапишем. Разсъждавам по аналогия с Java и C#.

Доколкото разбирам има дефолтен деструктор. Най-вероятно долу изглежда нещо от рода на:
~MyClass()

{

    deleteFromMemory();

}

 

Ако обаче ние имплементираме деструктор, фактически овърлоудваме дефолтния. Примерно правим

~MyClass()

{

    cout << "MyClass has been destroyed";

}

 

Обаче никъде в нашия деструктор ние не му казваме да си зачисти паметта. Не трябва ли вътре в него да извикаме деструктора на базовия метод или нещо такова?

Тагове:
1
C++ Programming
RoYaL avatar RoYaL Trainer 6847 Точки

Ами защо не го тестваш? На този въпрос лесно можеш да намериш отговор като тестваш следните два сценария:

Сценарий 1:

    1. Създаваш клас без деструктор

    2. Създаваш обект от този клас

    3. Изтриваш обекта

    4. Извикваш някакъв член на този обект и гледаш резултата

Сценарий 2:

    1. Създаваш клас с деструктор

    2. Създаваш обект от този клас

    3. Изтриваш обекта

    4. Извикваш някакъв член на този обект и гледаш резултата

 

Ако и в двата сценария не получаваш верните данни от извикания член, например Person::getName() вместо да върне "pesho" връща произволно алокирана памет, значи и в двата случая се изтрива този обект от паметта.

TL;DR: Да, дори и просто да принтираш в деструктора, пак ще се изтрие от паметта.

1
Hristo_Penchev avatar Hristo_Penchev 389 Точки

Благодаря за отговора. Съвсем начинаещ съм в С++ и през ума ми не беше минал този начин за тестване. Малко ми е странно, че пак ще се изтрие в паметта, понеже разсъждавам с концепциите от C#. Как се случва това, при положение, че изцяло променяме имплементацията на метода?

1
RoYaL avatar RoYaL Trainer 6847 Точки

Предполагам, че извикването на деструктор метода е в допълнение към това, че се изтрива обекта, а не вместо това. Та вероятно потокът е: "Освободи паметта и извикай, ако има написани деструктори".

1
asparuh.k avatar asparuh.k 16 Точки

Мисля че освобождаването на памет не означава че данните в паметта непременно трябва да се заменят с произволни. Просто паметта става свободна за ползване. Може пак да ти покаже "pesho", но паметта да е освоободена. Това ако правилно съм разбрал случая.

Иначе като пренаписваш деструктори мисля че трябва да се грижиш да разрушаваш обекти които си заделил в heap-a. Също да затваряш потоци към файлове или да затваряш мрежови потоци. Ако например си си направил някакъв обект в конструктора без да ползваш new не би трябвало да го мислиш.

3
Filkolev avatar Filkolev 4482 Точки

Аналогията с Java/C# не е правилна, защото там имаш Garbage Collector-и и не се грижиш за освобождаване на паметта.

Идеята е да освободиш ресурси ако обектът, който бива унищожен, е получил такива. Т.е. аз както разбирам нещата, това не е механизъм да освободиш паметта на самия обект (това, което се пази в полетата), а някакви други ресурси. Затова в общия случай деструкторите са празни.

Аз си го представям по-скоро като cleanup функция - така ми е по-ясно какво прави. Думата destructor ми навява мисли, че това е мястото, където се унищожава обекта, а това не е така; това е метод, който се извиква в процеса на унищожаване, а не методът за самото унищожаване.

3
06/06/2016 22:20:20
M.Yankov avatar M.Yankov 52 Точки

И аз имам един въпрос за деструкторите. Питам тук за да не отварям нова тема: Кода е следния:
 

inline ~Building()
{
    printf("Building destructor called for %s \n", _companyName); // strange symbols
    cout << "Building destructor called for " << _companyName << endl; // normal output
}

 

когато ползавм printf() в деструктура ми принтира странни символи от сорта на на ╞╟╚¶, което си мисля че, е рефернция към памета или нещо от подобно. А когато извиквам чрез cout всичко е нормално.
Някой може ли да разясни защо се получава така?

1
jicata avatar jicata Trainer 7 Точки

Въпроса всякаш не е свързан конкретно с деструктурите а по-скоро с плейсхолдърите в printf(). Тъй като аз срещнах нещо подобно днес, направих един кратък рисърч, който ме доведе до C++ Reference - printf(). Това което открих е, че плейсхолдъра, който принципно очакваме (от Java поне) да отговаря на стринг - %s  всъщност приема пойнтър към character - *char, даже по-конкретно:

The argument must be a pointer to the initial element of an array of characters

Съответно техният пример е  

const char* s = "Hello";

което при 

printf("%s World", s);

принтира "Hello World". С други думи в твоя случай, просто можеш да използваш или char* name = .... или char name[] = ... и играта спи :) Поздрави!

 

1
CharlieScarver avatar CharlieScarver 33 Точки

Плейсхолдъра %s отговаря за const char*, а не за std::string.
В printf няма плейсхолдър за std::string.
1) Едното решение е, както jicata е казал, да използваш char*.

2) Втори вариант е да ползваш std::string и като принтираш (с printf) да ползваш c_str(), което ще преобразува std::string-a ти в char*. (не знам колко е бавно/бързо)
 

printf("Person %s destroyed\n", this->name.c_str());

 

1
M.Yankov avatar M.Yankov 52 Точки

Мерси за отговорите и двата начина, които дадохте работят. Естествено сега ми изникват още въпроси: от сорта на има ли значение как се деклариара променливата ? явно няма значение къде точно е поставен оператора *

char* name;
char *     name;
char *name;

 

 

 

 

0