Loading...

Във форума е въведено ограничение, което позволява на потребителите единствено да разглеждат публикуваните въпроси.

Jovanna avatar Jovanna 186 Точки

C++ Advanced, Task07_05_Linked_List - защо ни е Node * prev? И къде бъркам в деструктора?

Здравейте,

не мога да разбера защо имаме тук и пойнтери назад, това възможност за обрато обхождане ли е? Повечето реализации, които намерих са с пойнтери с връзка само за напред, защо ни трябват и за назад?

Kak да разпиша деструктора, kъде бъркам тук или е правилно разписан?

List::~List() {   
    if (!this->size != 0) {
        Node * tempH = this->head;                
        this->tail = NULL;                       // Toва зануляване тук вярно ли е? , мисля че е nullptr  this->tail за първия елемент ??
        Node * tempT = this->tail;
        while (tempH->getNext() != NULL) {
            tempT = tempH;
            tempH = tempH->getNext();
            delete tempT;
        }
        delete tempH;
    }

//имаме:

class Node {
    private:
        int value;
        Node * prev;
        Node * next;

и полета на клас List:

    Node * head;
    Node * tail;
    size_t size;

Поздрави!

 

Тагове:
0
C++ Programming 23/10/2018 17:24:50
MartinBG avatar MartinBG 4803 Точки

Коментарите на kolioi относно липсата на нужда от нулирането на поинтъри в деструктора, ме провокираха да се зачета по-подробно по темата, за което му благодаря! :)

По време на лекцията зададох уточняващ въпрос за ситуации, при които може да достъпим полета/методи на унищожен обект и как сетването на поинтърите на nullptr би ни помогнало, и отговорът който получих ми се стори смислен към момента, но след прочетеното съм убеден, че kolioi е прав, че това излишно.

Както се оказва, това не само е излишно, но е опасно и е лоша идея/практика:

- Допълнителни операции, които бавят

- Повече код -> по-трудно четене, нужда от поддържане, възможност за грешки

- Компилаторът в Release най-вероятно ще ги оптимизира, т.е. премахне, защото са ненужни

- В Debug компилаторът често презаписва освободените указателите с някаква известна нему стойност, която да улесни дебъгването

- След деструктора обектът вече не съществува. Всеки опит да се достъпи той или паметта, която е ползвал е недефинирано поведение, като е много вероятно тази памет вече да се ползва от друг обект, т.е. и нашия nullptr да е презаписан, което допълнително обезсмисля сетването му

- Ако по някаква причина паметта все още не е променена при опита ни да я достъпим след деструктура и сме сетнали пойнтъра на nullptr, всъщност може да прикрием бъг, който иначе ще хванем (например двойно освобождаване на памет, което може да се случи при повторно извикване на деструктора, но не само)

 

Накратко - няма ситуация, при която сетването на nullptr на указатели към освободена в деструктора памет да носи някаква полза. Най-вероятно идеята е дошла за подсигуряване срещу достъп до (вече) чужда памет, но както по-горе споменах, тази сигурност е измамна и само прикрива тези проблеми. Ситуация, при която външен код държи указател към вътрешни ресурси на обект, върху чиито живот няма контрол, е грешка в дизайна и nullptr не е решение.

Горното разбира се с пълна сила важи и за ресетването на други полета в деструктора (напр. size = 0) - това също е излишно, защото всеки достъп до обекта след деструктора е недефинирано поведение.

 

Още веднъж благодаря на kolioi за коментара, който ме провокира да се зачета по темата!

 

Няколко теми по въпроса: 

do-i-have-to-set-pointer-to-nullptr-in-destructor

is-it-worth-setting-pointers-to-null-in-a-destructor

is-the-c-compiler-optimizer-allowed-to-break-my-destructor-ability-to-be-calle

 

3
24/10/2018 16:15:05
kolioi avatar kolioi 641 Точки

Благодаря за коментара. Линковете са интересни. Аз просто се ръководя от правилото, че един пойнтер го нулираме само ако след това ще го използваме отново. Обаче след като се извика деструктора, обекта не съществува повече и няма как да използваме пойнтера (нямаме достъп до него чрез обекта). С две думи: няма обект - няма проблем, както казваше един мустакат чичко wink

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