wyjątek na wywołaniu metody klasy

wyjątek na wywołaniu metody klasy
K0
  • Rejestracja:ponad 4 lata
  • Ostatnio:prawie 2 lata
  • Postów:29
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

Kopiuj
#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

Kopiuj
#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

AK
prawie na pewno null pointer
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:2 dni
  • Lokalizacja:Szczecin
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

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

czyli

Kopiuj
pointer->data

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

Kopiuj
    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ę:


edytowany 1x, ostatnio: kq
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:3 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
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

Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
edytowany 7x, ostatnio: KamilAdam
kq
Implementacja w pliku nagłówkowym to konieczność dla szablonów niestety. Zobaczymy jak moduły zmienią sytuację.
KamilAdam
Smutny to język :(
Althorion
Nie bez powodu się mówi, że C++ to próba stworzenia ośmiornicy (sensownego języka obiektowego) przez przybicie dodatkowych nóg do psa (C)… A im nowszy standard, tym coraz gorzej ciąży ta kompatybilność wsteczna. Co gorsza, nie zapowiada się na próbę zerwania z nią.
K0
  • Rejestracja:ponad 4 lata
  • Ostatnio:prawie 2 lata
  • Postów:29
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ć.

lion137
  • Rejestracja:około 8 lat
  • Ostatnio:2 minuty
  • Postów:4891
0

JAkie IDE, jak ustawisz breakpointy?


K0
visual studio 2019, próbowałem ustawiać je już chyba wszędzie.
enedil
  • Rejestracja:ponad 11 lat
  • Ostatnio:około 18 godzin
  • Postów:1027
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

K0
Jest taka, ale używam w niej break po if'ach.
enedil
no nie, mówię że masz nieskończoną pętlę faktycznie, bo mi w debuggerze tak pokazuje
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:2 dni
  • Lokalizacja:Szczecin
2

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

Sprawdźmy to


Zobacz pozostałe 5 komentarzy
kq
Hah, nie wiedziałem że mi z muzyką złapie ekran. Dziś mam po prostu synthwave do pracy.
Althorion
A, taka magia. To teraz ma sens. :D Już myślałem, że ręcznie dodawałeś.
kq
Co to to nie, dodawałem kiedyś soundtrack za pomocą ffmpega ale to było pół godziny googlowania.
enedil
w sumie to nie ma szansy przejść przez search, bo to bezwarunkowo zmienia się w nieskończoną rekurencję
enedil
  • Rejestracja:ponad 11 lat
  • Ostatnio:około 18 godzin
  • Postów:1027
0

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

Kopiuj
==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).
K0
  • Rejestracja:ponad 4 lata
  • Ostatnio:prawie 2 lata
  • Postów:29
0

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

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:2 dni
  • Lokalizacja:Szczecin
3

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


edytowany 1x, ostatnio: kq
K0
  • Rejestracja:ponad 4 lata
  • Ostatnio:prawie 2 lata
  • Postów:29
0

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

Kopiuj
[...]
	~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;
			}
		}
	}
[...]
};
edytowany 1x, ostatnio: kategoria000
enedil
Masz wyciek w add_new, więc nie załatwi to problemu, bo pamięć wycieka jeszcze zanim obiekt umrze.
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:2 dni
  • Lokalizacja:Szczecin
0

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


Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)