Професионална програма
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
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.