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

0

Я обновлялся с помощью C++ и пытаюсь создать связанный класс списка с двумя строками, в котором есть функция, которая будет сортировать элементы в списке по алфавиту. Я отправляю их в swap-функцию, передавая указатели на два элемента в сравниваемом списке, а затем они продают информацию указателя, чтобы список был "реорганизован", как показано здесь:

void LinkedList::swapItem(LinkedList* a, LinkedList* b)
{
LinkedList temp = *a;

a->pNext = b->pNext;

// if statement to prevent b->pNext from pointing back to b if items are 'adjecent' to eachother in the list

if(b == temp.pNext)
{
    b->pNext = a;
}
else
{
    b->pNext = temp.pNext;
}

a->idNum = b->idNum;
b->idNum = temp.idNum;
}

Эта функция вызывается другой функцией, которая должна проверять значения строки "фамилия" и определять, нужно ли их заменять. Затем он переключает итераторы (которые являются указателями, которые были переданы функции свопинга), и предполагается продолжить их через список, но после функции подкачки итераторы/указатели указывают на одно и то же место, но данные в объектах просто ушел, потому что деструктор вызывается в конце функции свопинга! почему он будет называть деструктор, когда объекты все еще используются? Есть ли способ сказать деструктору остановиться? Вот код для сортировки по алфавиту:

LinkedList* LinkedList::sortAlpha()
{
LinkedList *top = this;
LinkedList *pItrA = this;
LinkedList *pItrB = this->pNext;
LinkedList *temp = NULL;

while(pItrA != NULL)
{
    while(pItrB != NULL)
    {
        if(pItrA->alphaOrder > pItrB->alphaOrder)
        {
            swapItem(pItrA, pItrB);
            temp = pItrA;
            pItrA = pItrB;
            pItrB = temp;
            temp = NULL;

            if(pItrB->idNum == 0)
            {
                // Tracks the pointer at the "top" of the list if pItrB is the new top item
                top = pItrB;
            }
        }
        pItrB = pItrB->pNext;
    }
    pItrA = pItrA->pNext;
}

return top;
}

Я знаю, что этот код, вероятно, очень грязный или в лучшем случае неэффективен, но я не слишком обеспокоен этим, потому что я просто пытаюсь понять, как все это работает и почему.

  • 0
    Частный деструктор может использоваться для предотвращения вызова деструктора (при условии, что наследства нет)!
  • 0
    @KaustavRay Это не верно для функции-члена, и это делает довольно трудным сделать их, кроме как с new ...
Показать ещё 3 комментария
Теги:
pointers

3 ответа

1
Лучший ответ

Это создает локальный временный LinkedList, инициализированный путем копирования a в него:

LinkedList temp = *a;

Когда это временное выходит из сферы действия, его деструктор вызывается. Это то, что должно произойти, и вы не можете остановить его, не устраняя временного.

Вы должны переписать свою функцию swap чтобы она не требовала сделать копию a таким образом. Кажется, что вы не можете сделать свою текущую функцию обмена правильной, если вы этого не сделаете.

Вероятно, одна из двух вещей возникает при создании этого временного:

  1. Конструктор копирования выполняет мелкую копию, выводя указатели из источника.
  2. Конструктор копирования делает глубокую копию в простых указателях и реплицирует структуру.
  3. Вы используете указатели с подсчетом ссылок и делаете что-то гораздо более интересное.

Неглубокая копия позволяет вам напрямую тестировать указатели, как и в вашей функции свопинга. Глубокая копия даст вам несвязанные указатели между двумя копиями. И # 3 кажется маловероятным на данный момент.

Затем, когда вы уничтожаете временное, может произойти пара разных вещей:

  1. Вы ничего не delete что приводит к потенциальным утечкам памяти.
  2. Вы удаляете всю цепочку, начиная с временной, стирая значительную часть вашего связанного списка (при условии мелкой копии).

Я предполагаю, что с тех пор, как вы пришли сюда, ситуация выглядит ближе к №2.


Включая мои дальнейшие мысли снизу: ваша логика свопа выглядит ошибочной. Чтобы поменять элементы в односвязном списке, вам нужно манипулировать next указателями предшественников на обмениваемые узлы, и у вас нет доступных для вас функций свопинга.

В этом случае вам лучше просто заменить остальных членов класса, а не манипулировать указателями. Если в вашем классе был большой объем данных, тогда вам может быть лучше с манипуляцией указателем, но вам нужно знать предшественников двух узлов, которые вы обмениваете (или, по крайней мере, указатель/ссылку на pNext в предшественники), чтобы сделать это правильно.

  • 0
    Хорошо, я понимаю, что вы говорите, я думаю. так что temp уничтожается, выходя из области видимости, и поскольку он содержит указатель на «b», а «b» теперь содержит указатель на «a», все данные уничтожаются ... Думаю, я могу это исправить. Благодарю.
  • 0
    @ManicCure: Для всеобщего блага я добавил несколько вероятных объяснений того, что происходит не так. Надеюсь это поможет.
Показать ещё 2 комментария
0

Джо З был прав с

Вы удаляете всю цепочку, начиная с временной, стирая значительную часть вашего связанного списка (при условии мелкой копии)

Поэтому я переписал функцию alphaSort для обработки всего:

LinkedList* LinkedList::sortAlpha()
{
bool sorted = false;

LinkedList* top = this;
LinkedList* prev = NULL;
LinkedList* itr = NULL;

while(sorted == false)
{
    prev = NULL;
    itr = top;
    sorted = true;

    while(itr != NULL)
    {
        if(itr->pNext != NULL && itr->alphaOrder > itr->pNext->alphaOrder)
        {
            LinkedList *temp = itr;
            LinkedList *tempNext = itr->pNext->pNext;

            if(itr->idNum == 0)
            {
                itr->idNum = itr->pNext->idNum;
                itr->pNext->idNum = 0;
                top = itr->pNext;
            }

            itr = itr->pNext;
            itr->pNext = temp;
            itr->pNext->pNext = tempNext;
            sorted = false;

            if(prev != NULL)
            {
                prev->pNext = itr;
            }
        }

        prev = itr;
        itr = itr->pNext;
    }
}

itr = top;
int idCounter = 0;

while(itr != NULL)
{
    itr->idNum = idCounter;
    idCounter++;
    itr = itr->pNext;
}

return top;
}

Благодарность за вклад каждого!

0

Переменная temp уничтожается и, по-видимому, уничтожает другие объекты LinkedList, на которые указывает. Вместо этого перепишите как:

void LinkedList::swapItem(LinkedList* a, LinkedList* b)
{
LinkedList* tmpNext = a->pNext;
auto tmpId = a->idNum; // I use auto because I don't know what type idNum is (int ?)

a->pNext = b->pNext;

// if statement to prevent b->pNext from pointing back to b if items are 'adjecent' to eachother in the list

if(b == tmpNext)
{
    b->pNext = a;
}
else
{
    b->pNext = tmpNext;
}

a->idNum = b->idNum;
b->idNum = tmpId;
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню