
Comportamiento extraño del Destructor()
Publicado por Chris (7 intervenciones) el 26/09/2023 18:22:52
Buenas a todos, estoy resolviendo problemas sobre Estructuras de Datos, tengo este archivo de encabezado de Lista Enlazada descargado de la web donde hago los ejercicios.
LinkedList.h
Este es una solución para uno de los ejercicios, comprobada con los test online, estoy haciendo mis propios test para aprender también sobre esto:
LL_find_middle_node.cpp
Este test funciona bien, lo pongo como ejemplo para comparar lo que ocurre con el siguiente ejercicio.
LL_find_k_node_from_end.cpp
En ambos casos cuando termina de ejecutarse el método Solution::method(), se llama al destructor de clase, entiendo que al pasar la lista por valor termina el ámbito de ejecución de la copia.
Puedo ver en el depurador como se destruye la lista original, ya que los punteros copia siguen apuntando a las mismas direcciones de memoria.
Lo curioso es que con el método Node* findMiddleNode(LinkedList l) al volver el flujo de ejecución al test_case, la lista original sigue ahí, aún habiendo visto como se destruía, y el test es superado.
Esto no pasa con el método Node* findKthFromEnd(int k, LinkedList l), la lista se destruye y el test no llega a terminar porque el puntero devuelto no apunta a una dirección válida (creo que esto es lo esperado en esta situación)
Puedo pasar la lista por referencia y funciona bien, pero me sorprende este comportamiento tan dispar. Más que una solución me gustaría entender que está pasando ya que ambos métodos son muy parecidos, ambos devuelven un puntero a un nodo, recorren la lista y no modifican su contenido.
¿Alguna idea?
Gracias
LinkedList.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
using namespace std;
class Node {
public:
int value;
Node* next;
Node(int value) {
this->value = value;
next = nullptr;
}
};
class LinkedList {
private:
Node* head;
Node* tail;
int length;
public:
LinkedList(int value) {
Node* newNode = new Node(value);
head = newNode;
tail = newNode;
length = 1;
}
~LinkedList() {
Node* temp = head;
while (head != nullptr) {
head = head->next;
delete temp;
temp = head;
}
}
void printList() {
Node* temp = head;
if (temp == nullptr) {
cout << "empty";
} else {
while (temp != nullptr) {
cout << temp->value;
temp = temp->next;
if (temp != nullptr) {
cout << " -> ";
}
}
}
cout << endl;
}
Node* getHead() {
return head;
}
Node* getTail() {
return tail;
}
int getLength() {
return length;
}
void makeEmpty() {
Node* temp = head;
while (head != nullptr) {
head = head->next;
delete temp;
temp = head;
}
tail = nullptr;
length = 0;
}
void append(int value) {
Node* newNode = new Node(value);
if (head == nullptr) {
head = newNode;
tail = newNode;
} else {
tail->next = newNode;
tail = newNode;
}
length++;
}
};
Este es una solución para uno de los ejercicios, comprobada con los test online, estoy haciendo mis propios test para aprender también sobre esto:
LL_find_middle_node.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution{
public:
static Node* findMiddleNode(LinkedList l) {
Node* slow = l.getHead();
Node* fast = slow;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
};
#define CATCH_CONFIG_MAIN
#include "../../catch.hpp"
TEST_CASE("Even number of elements", "[even_test]"){
LinkedList l(1);
l.append(2);
l.append(3);
l.append(4);
l.append(5);
l.append(6);
Node *middle = Solution::findMiddleNode(l);
REQUIRE(middle->value == 4);
}
Este test funciona bien, lo pongo como ejemplo para comparar lo que ocurre con el siguiente ejercicio.
LL_find_k_node_from_end.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution{
public:
static Node* findKthFromEnd(int k, LinkedList l){
Node *fast = l.getHead();
Node *slow = fast;
for(int i = 0; i < k; ++i){
if(fast == nullptr){
return nullptr;
}
fast = fast->next;
}
while(fast != nullptr){
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
#define CATCH_CONFIG_MAIN
#include "../../catch.hpp"
TEST_CASE("K Second From End", "[KSecondFromEnd]"){
LinkedList l(1);
l.append(2);
l.append(3);
l.append(4);
l.append(5);
Node *result = Solution::findKthFromEnd(2, l);
REQUIRE(result->value == 4);
}
En ambos casos cuando termina de ejecutarse el método Solution::method(), se llama al destructor de clase, entiendo que al pasar la lista por valor termina el ámbito de ejecución de la copia.
Puedo ver en el depurador como se destruye la lista original, ya que los punteros copia siguen apuntando a las mismas direcciones de memoria.
Lo curioso es que con el método Node* findMiddleNode(LinkedList l) al volver el flujo de ejecución al test_case, la lista original sigue ahí, aún habiendo visto como se destruía, y el test es superado.
Esto no pasa con el método Node* findKthFromEnd(int k, LinkedList l), la lista se destruye y el test no llega a terminar porque el puntero devuelto no apunta a una dirección válida (creo que esto es lo esperado en esta situación)
Puedo pasar la lista por referencia y funciona bien, pero me sorprende este comportamiento tan dispar. Más que una solución me gustaría entender que está pasando ya que ambos métodos son muy parecidos, ambos devuelven un puntero a un nodo, recorren la lista y no modifican su contenido.
¿Alguna idea?
Gracias
Valora esta pregunta


0