Я обновлялся с помощью 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;
}
Я знаю, что этот код, вероятно, очень грязный или в лучшем случае неэффективен, но я не слишком обеспокоен этим, потому что я просто пытаюсь понять, как все это работает и почему.
Это создает локальный временный LinkedList
, инициализированный путем копирования a
в него:
LinkedList temp = *a;
Когда это временное выходит из сферы действия, его деструктор вызывается. Это то, что должно произойти, и вы не можете остановить его, не устраняя временного.
Вы должны переписать свою функцию swap
чтобы она не требовала сделать копию a
таким образом. Кажется, что вы не можете сделать свою текущую функцию обмена правильной, если вы этого не сделаете.
Вероятно, одна из двух вещей возникает при создании этого временного:
Неглубокая копия позволяет вам напрямую тестировать указатели, как и в вашей функции свопинга. Глубокая копия даст вам несвязанные указатели между двумя копиями. И # 3 кажется маловероятным на данный момент.
Затем, когда вы уничтожаете временное, может произойти пара разных вещей:
delete
что приводит к потенциальным утечкам памяти.Я предполагаю, что с тех пор, как вы пришли сюда, ситуация выглядит ближе к №2.
Включая мои дальнейшие мысли снизу: ваша логика свопа выглядит ошибочной. Чтобы поменять элементы в односвязном списке, вам нужно манипулировать next
указателями предшественников на обмениваемые узлы, и у вас нет доступных для вас функций свопинга.
В этом случае вам лучше просто заменить остальных членов класса, а не манипулировать указателями. Если в вашем классе был большой объем данных, тогда вам может быть лучше с манипуляцией указателем, но вам нужно знать предшественников двух узлов, которые вы обмениваете (или, по крайней мере, указатель/ссылку на pNext
в предшественники), чтобы сделать это правильно.
Джо З был прав с
Вы удаляете всю цепочку, начиная с временной, стирая значительную часть вашего связанного списка (при условии мелкой копии)
Поэтому я переписал функцию 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;
}
Благодарность за вклад каждого!
Переменная 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;
}
new
...