wyjątek na wywołaniu metody klasy

0

Nie wiem co mogłoby być przyczyną, ponieważ get_root() nie robi problemów, a display() bez problemu iteruje po drzewie i odczytuje wszystkie dane z węzłów.

The thread 0x4cc8 has exited with code 0 (0x0).
Exception thrown at 0x005A109A in BST.exe: 0xC0000005: Access violation reading location 0x0000000C.

main.cpp

#include "bst.h"
#include <iostream>
#include <time.h>

using namespace std;

int num() {
	return rand() % 100;
}

int main()
{
	srand(time(NULL));
	int size = 4;
	Bst<int>* drzewo = new Bst<int>();
	for (int i = 1; i < size; i++){
		drzewo->add_new(num());
        }
	drzewo->add_new(15);
	cout << (&drzewo->get_root())->data;
	drzewo->display();

	cout << (drzewo->search(&drzewo->get_root(), 15))->data << endl;      // tutaj wyrzuca wyjątek

	delete drzewo;
	return 0;
}

bst.h

#include <time.h>
#include <iostream>

template <class T>

class Bst {
	struct Node {
		Node(T value) : data(value) {}
		Node* parent = nullptr;
		Node* left = nullptr;
		Node* right = nullptr;
		T data;
		int index = 1;
		int depth = 0;
	};

	unsigned int size = 0;
	unsigned int height = 0;
	unsigned int deepest_nodes_counter = 1;
	Node* root = nullptr;
	unsigned int last_index = 1;

public:

	void add_new(T value) {
		Node* temp = new Node(value);
		temp->index = last_index++;
		if (!root) {
			root = temp;
			size++;
		}
		else {
			auto current = root;
			for (unsigned int i = 1; true; i++) {
				auto last = current;
				if (value == current->data) {
					temp->parent = current;
					if (current->left) {
						temp->left = current->left;
					}
					current->left = temp;
					temp->depth = i;
					if (i > height) {
						height = i;
						deepest_nodes_counter = 1;
					}
					else if (i == height)
						deepest_nodes_counter++;
					size++;
					break;
				}
				current = (value < current->data) ? current->left : current->right;
				if (!current) {
					temp->parent = last;
					if (value < last->data)
						last->left = temp;
					if (value > last->data)
						last->right = temp;
					temp->depth = i;
					if (i > height) {
						height = i;
						deepest_nodes_counter = 1;
					}
					else if (i == height)
						deepest_nodes_counter++;
					size++;
					break;
				}
			}
		}
	}

	//pre-order search
	Node* search(Node* node, T value) {
		auto current = root;
		if (current->data == value) {
			return current;
		}
		else {
			search(current->left, value);
			search(current->right, value);
			return nullptr;
		}
	}
};	

całość kodu: https://godbolt.org/z/xe81zh

3

search() zwraca nullptr. Debugger w rękę i do dzieła.

Przy okazji, warto próbować rozumieć co znaczą takie komunikaty:

0xC0000005: Access violation reading location 0x0000000C.

access violation przy odczycie offsetu 12 (C16) bajtów od zera.

Sam zauważyłeś, że jest to

(drzewo->search(&drzewo->get_root(), 15))->data

czyli

pointer->data

Co jest spójne na 32-bitowej architekturze z offsetem data

    struct Node {
        Node(T value) : data(value) {}
        Node* parent = nullptr;
        Node* left = nullptr;
        Node* right = nullptr;
        T data;
        int index = 1;
        int depth = 0;
    };

Aha, i ponawiam apel o lekturę:

0

Na C++ się nie znam, ale czytając odpowiedzi to mogę powiedzieć:

  • implementacja w pliku *.h
  • debugowałeś?
  • rozbij tą linię cout << (drzewo->search(&drzewo->get_root(), 15))->data << endl; na więcej linii do lepiej będziesz wiedział gdzie rzuca wyjątek
  • A tak w ogóle to jeśli search zwraca nullptr, a potem na tym robisz -> data to czego się spodziewasz? Nie uwzględniasz przypadku gdy nie znajdziesz
0

Właśnie problem w tym że debugger nie chce wejść do żadnej z metod wywoływanych na tej linii, tylko zatrzymuje się w main( ) i nie wiedziałem co w tej kwestii zrobić.

0

JAkie IDE, jak ustawisz breakpointy?

0

Masz tam również gdzieś nieskończoną pętlę, backtrace w GDB wywala mi na kilkadziesiąt tysięcy poziomów głębokości

2

debugger nie chce wejść do żadnej z metod wywoływanych na tej linii, tylko zatrzymuje się w main( )

Sprawdźmy to

0

A swoją drogą, uwaga o ręcznej alokacji jak najbardziej słuszna:

==26441==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x7faa96d6b067 in operator new(unsigned long) (/lib64/libasan.so.6+0xb2067)
    #1 0x401894 in Bst<int>::add_new(int) /tmp/bst.h:31
    #2 0x7faa00000000  (<unknown module>)

Indirect leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x7faa96d6b067 in operator new(unsigned long) (/lib64/libasan.so.6+0xb2067)
    #1 0x401894 in Bst<int>::add_new(int) /tmp/bst.h:31
    #2 0x7faa00000001  (<unknown module>)

Indirect leak of 40 byte(s) in 1 object(s) allocated from:
    #0 0x7faa96d6b067 in operator new(unsigned long) (/lib64/libasan.so.6+0xb2067)
    #1 0x401894 in Bst<int>::add_new(int) /tmp/bst.h:31
    #2 0x7faa00000000  (<unknown module>)

SUMMARY: AddressSanitizer: 120 byte(s) leaked in 3 allocation(s).
0

o co biega debuggerowi? ja serio nie mogę wejść do tych metod

3

Dlaczego kompilujesz w trybie release podczas debugowania? (i ma jakiś cel kompilacja x86 w 2020 roku?)

0

Czy umieszczenie metody która usuwa wszystkie elementy z drzewa w destruktorze załatwi problem wycieków?

[...]
	~Bst() {
		rm_all(get_root());
	}

	void rm_all(Node* node) {
		if (node != nullptr)
		{
			rm_all(node->left);
			rm_all(node->right);
			if (node != root) {
				if (node->left == nullptr && node->right == nullptr) {
					if (node->parent->left == node)
						node->parent->left = nullptr;
					else
						node->parent->right = nullptr;
					delete node;
				}
			}
			else {
				delete node;
			}
		}
	}
[...]
};
0

Cały czas powinieneś przestrzegać https://en.cppreference.com/w/cpp/language/rule_of_three

1 użytkowników online, w tym zalogowanych: 0, gości: 1