Segmentation fault issues when creating a Binary Search Tree - c++

Ill start out with giving all the code I think is relevant. Basically a Binary Search Tree was already defined that worked and we need to add a parent node functionality. I have done this but I keep getting segmentation faults.
template <class TKey>
class bst {
private:
struct node {
node() { key=TKey(); link[0]=link[1]=NULL; parent=NULL; }
operator TKey () { return key; }
void print();
TKey key;
node *link[2];
node *parent;
};
public:
class iterator {
public:
private:
friend class bst<TKey>;
node *p;
};
node *prev_node;
iterator begin() { }
iterator end() { }
bst() { Troot=NULL; }
~bst() { clear(Troot); }
bool empty() { return Troot==NULL; }
void clear() { clear(Troot); Troot=NULL; }
void erase(TKey &key);
void insert(TKey &key);
void print_inorder() { print_inorder(Troot); }
void print_bylevel();
private:
void clear(node *);
node *minmax_key(node *, int);
node *erase(node *, TKey &);
node *insert(node *, TKey &);
void print_inorder(node *);
node *Troot;
};
Thats the Class Definition.
template <class TKey>
void bst<TKey>::insert(TKey &key)
{
Troot = insert(Troot, key);
}
template <class TKey>
class bst<TKey>::node *bst<TKey>::insert(node *T, TKey &key)
{
cout << "insert1" << endl;
if (T == NULL) {
T = new node;
T->key = key;
if (prev_node != NULL)
T->parent = prev_node;
cout << T->parent->key;
} else if (T->key == key) {
cout << "key " << key << " already in tree" << endl;
} else {
prev_node = T;
int dir = T->key < key;
T->link[dir] = insert(T->link[dir], key);
}
return T;
}
These are the insert functions. Im guessing I am doing something out of order because I am still really rusty with recursion. When I run the test program that uses the tree it outputs the inser1 line but then gives a seg fault. So i know it is messing up on the first insert. any help? If you need to see the rest of the code I can put it up but itll be a lot of stuff that isnt actually relevent to the changes Ive made.

I'm thinking the segfault is on this line
cout << T->parent->key;
If T->parent is null, which it is if T is the newly created root (ie if prev_node == NULL), then you can't access the 'key' of a NULL value.
NOTE: Be aware that I have only skimmed your code, so this is only the first thing I have come across, there could be other bugs.
EDIT:
What do you mean by "I am still having problems", what problems are you having?
It probably isn't how I would implement a BST insert but I can't see anything jumping out saying it is wrong.
How I would implement it is rather than having a global variable prev_node, I would probably change your code like so:
template <class TKey>
void bst<TKey>::insert(TKey &key)
{
// Note that I have an initial prev_node of NULL
Troot = insert(Troot, key, NULL);
}
// Note the extra function parameter
template <class TKey>
class bst<TKey>::node *bst<TKey>::insert(node *T, TKey &key, node *prev_node)
{
cout << "insert1" << endl;
if (T == NULL) {
T = new node;
T->key = key;
// I have a habit of always using braces, so that it is easier to read.
// This would have helped you with your initial problem.
if (prev_node != NULL) {
T->parent = prev_node;
}
//cout << T->parent->key;
} else if (T->key == key) {
cout << "key " << key << " already in tree" << endl;
} else {
int dir = T->key < key;
T->link[dir] = insert(T->link[dir], key, T); // Note diff here
}
return T;
}
Unless you are using prev_node somewhere else.
But this shouldn't change how the insert works, unless in your implementation:
prev_node is not null initially for some reason (which would be the case on successive inserts, unless you are resetting it somewhere else).
something is changing prev_node while you are using it (think thread-safety)

Related

Creating a unified search function for a binary search tree

I'm trying to create a search function in a binary search tree that can be used by both the insert and search functions.
I tried passing my cursor as a reference
template<class key_type, class data_type>
bool binary_tree<key_type, data_type>::internal_search(node *& cursor, key_type query) {
if (cursor == NULL) {
return false;
}else if (cursor->key == query) {
return true;
}
if (cursor->key < query) {
internal_search(cursor->left, query);
}
else {
internal_search(cursor->right, query);
}
}
Here is the insert function I'm trying to use it in
template<class key_type, class data_type>
void binary_tree<key_type, data_type>::insert(key_type key_in, data_type data_in) {
node * local_cursor = start;
if (!internal_search(local_cursor, key_in)) {
local_cursor = new node;
local_cursor->key = key_in;
local_cursor->data = data_in;
local_cursor->left = NULL;
local_cursor->right = NULL;
size++;
}
else {
std::cout << "entry already present" << std::endl;
}
}
Here is the search function I'm trying to use it in
template<class key_type, class data_type>
data_type binary_tree<key_type, data_type>::search(key_type query) {
node * local_cursor = start;
if (internal_search(local_cursor, query)) {
return local_cursor->data;
}
std::cout << "search query not found" << std::endl;
}
Neither passing through as a reference or returning as a value have worked
I don't understand why when I run this code the start pointer is always NULL when inserting a new value into the binary search tree.
I also tried rewriting the code with the internal_search function returning a node pointer but that didn't work either.
Why does start point to NULL everytime instead of the new node I assigned it to?
here's the header if that might help
#pragma once
template <class key_type, class data_type>
class binary_tree
{
private:
struct node {
key_type key;
data_type data;
node * left;
node * right;
};
node * start;
int size;
bool internal_search(node *, key_type);
void print_preorder(node * cursor = start);
void file_preorder( std::ofstream&, node *);
void file_inorder(std::ofstream&, node *);
void print_inorder_pri(node *);
void print_postorder(node *);
void file_postorder(std::ofstream&, node *);
public:
binary_tree();
void insert(key_type);
void remove();
bool is_empty();
data_type search(key_type);
void print_preorder();
void file_preorder(std::ofstream&);
void print_inorder();
void file_inorder(std::ofstream&);
void print_postorder();
void file_postorder(std::ofstream&);
void print_level();
bool load_file(std::string);
void save_file(std::string);
~binary_tree();
};
After some trivial modifications (including the one related to #Scheff's comment), I got it compiled.
However, start was effectively always equal to NULL.
I discovered that the problem was that ìnternal_search was always returning NULL, i.e.
the value of the node* before node creation and not the address of node* where to create the new node. Therefore, it was needed to replace (node* &) by (node** &).
Here is the code that seems to work, (with a main() for test) at least for the simple test searchthat was causing problem to the PO. Some work must be done to improve (e.g. a recursive insert) and complete the code (e.g. to delete the object binary_tree) but this is out of the scope of the question (fortunately!).
#include <iostream>
template <class key_type, class data_type>
class binary_tree
{
private:
struct node {
key_type key;
data_type data;
node* left = NULL;
node* right = NULL;
};
node* start = NULL;
int size = 0;
bool internal_search(node** &cursor, key_type);
//void print_preorder(node * cursor = start);
//void file_preorder( std::ofstream&, node *);
void file_inorder(std::ofstream&, node *);
void print_inorder_pri(node *);
void print_postorder(node *);
void file_postorder(std::ofstream&, node *);
public:
binary_tree() {};
void insert(key_type, data_type);
void remove();
bool is_empty();
data_type search(key_type);
//void print_preorder();
void file_preorder(std::ofstream&);
void print_inorder();
void file_inorder(std::ofstream&);
void print_postorder();
void file_postorder(std::ofstream&);
void print_level();
bool load_file(std::string);
void save_file(std::string);
void print_start () {std::cout << start << "\n";} // Added
//~binary_tree();
};
template<class key_type, class data_type>
bool binary_tree<key_type, data_type>::internal_search (node** &cursor, key_type query) {
if (*cursor == NULL) {
return false;
} else if ((*cursor)->key == query) {
return true;
}
if ((*cursor)->key < query) {
cursor = &((*cursor)->left);
return internal_search(cursor, query);
} else {
cursor = &((*cursor)->right);
return internal_search(cursor, query);
}
}
template<class key_type, class data_type>
void binary_tree<key_type, data_type>::insert(key_type key_in, data_type data_in) {
node** local_cursor = &start;
if (!internal_search(local_cursor, key_in)) {
*local_cursor = new node;
(*local_cursor)->key = key_in;
(*local_cursor)->data = data_in;
size++;
}
else {
std::cout << "entry already present" << std::endl;
}
}
template<class key_type, class data_type>
data_type binary_tree<key_type, data_type>::search(key_type query) {
node** local_cursor = &start;
if (internal_search(local_cursor, query)) {
return (*local_cursor)->data;
}
std::cout << "search query not found" << std::endl;
return 0;
}
int main() {
binary_tree<int,int> tree;
tree.insert (0,0);
tree.insert (2,3);
tree.insert (-2,3);
tree.insert (-1,-1);
std::cout << "start = ";
tree.print_start();
std::cout << tree.search(2) << "\n";
return 0;
}

How do I get the number of leaves on my binary tree code?

I have been getting 0 as the number of leaves on my binary tree. I do not see any problems with my code and would like some feedback. Thank You!:)
MAIN.cpp
int main()
{
BinaryTree <int> a;
a.insertNode(13);
a.insertNode(28);
a.insertNode(8);
a.insertNode(14);
cout << a.numNodes() << endl;
cout << a.numLeafNodes() << endl;
cout << a.height() << endl;
cout << a.getWidth() << endl;
system("PAUSE");
}
Binary Tree Class header. This is my class that has the functions.
template<class T>
class BinaryTree
{
private:
struct TreeNode
{
T value;
TreeNode *left;
TreeNode *right;
};
TreeNode *root;
void insert(TreeNode *&, TreeNode *&);
int countNodes(TreeNode *&nodePtr);
void countLeaves(TreeNode* nodePtr);
int getTreeHeight(TreeNode* nodePtr);
int width(TreeNode* nodePtr);
public:
BinaryTree()
{
root = nullptr;
}
void insertNode(T);
int numNodes();
int numLeafNodes();
int height();
int getWidth();
};
My Functions for getting the number of leaves. This is Where I am not sure the issue is.
template <class T>
int BinaryTree<T>::numLeafNodes()
{
int leafCount = 0;
countLeaves(root);
return leafCount;
}
template <class T>
void BinaryTree<T>::countLeaves(TreeNode* nodePtr)
{
if (nodePtr)
{
countLeaves(nodePtr->left);
countLeaves(nodePtr->right);
if (nodePtr->left == NULL && nodePtr->right == NULL)
{
int leafCount = 0;
leafCount = leafCount + 1;
}
}
}
template <class T>
int BinaryTree<T>::numLeafNodes()
{
int leafCount = 0;
This defines a variable named leafCount.
countLeaves(root);
This doesn't change the leafCount defined above.
return leafCount;
...so this returns leafCount, still holding the value 0.
template <class T>
void BinaryTree<T>::countLeaves(TreeNode* nodePtr)
{
if (nodePtr)
{
countLeaves(nodePtr->left);
countLeaves(nodePtr->right);
if (nodePtr->left == NULL && nodePtr->right == NULL)
{
int leafCount = 0;
This defines another, completely separate variable, that also happens to be named leafCount.
leafCount = leafCount + 1;
This increments the variable defined immediately above.
}
...and here this leafCount goes out of scope and is destroyed, without affecting anything outside its scope at all (and since there's no observable effect from this leafCount being created, incremented, or destroyed, chances are the the compiler will optimize all that out).
What you'd typically want would be something like returning a value that indicates the number of leaf nodes encountered. This would figure out whether the current node is a leaf node, and if so return 1. Otherwise, it would return the sum of the number of leaf nodes of its left and right sub-trees.

Search Function Using Derived Classes in a Hash Table

I am having a bit of an issue with my derived classes and how they utilize the search function that they inherit from their parent class.
Here is my .h file
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
#define TABLESIZE 13
#ifndef HASH_H
#define HASH_H
namespace HTGroup
{
template<class T>
class HashTable
{
protected:
struct item {
T x;
item* next;
};
item* HT[TABLESIZE];
virtual int hash(T key) = 0;
virtual int collision(T key, int &value) = 0;
public:
HashTable();
virtual void printGrid();
void insert(T key);
void remove(T key);
void search(T key);
int indexItems(int index);
};
template<class T>
class DHT1 : public HashTable<T>
{
protected:
int hash(T key);
int collision(T key, int &value);
struct item {
T x;
item* next;
};
item* HT[TABLESIZE];
public:
DHT1();
void printGrid();
};
template<class T>
class DHT2 : public HashTable<T>
{
protected:
int hash(T key);
int collision(T key, int &value);
struct item {
T x;
item* next;
};
item* HT[TABLESIZE];
public:
DHT2();
void printGrid();
};
}
#endif
Here is what I have implemented for the search function:
template<class T>
void HashTable<T>::search(T key)
{
int index = hash(key);
bool foundKey = false;
string item;
item* temp = HT[index];
while(temp != NULL)
{
if(temp->x == key)
{
foundKey = true;
item = temp->x;
}
temp = temp->next;
}
if(foundKey == true)
{
cout << "Item was found." << endl;
}
else
{
cout << "Item was not found." << endl;
}
}
And this is how I am calling the function in my main:
hashy1.search(item);
I am getting an error from the compiler with this line from my search implementation:
item* temp = HT[index];
Giving me this error:
[Error] 'temp' was not declared in this scope
From my understanding whenever an object of a derived class is calling the search function it is getting confused with whether or not the pointer created is of the parent class or the derived class.
The weird thing though is that it has let me create other pointers in my remove function without any issues and it works fine:
template<class T>
void HashTable<T>::remove(T key)
{
int index = hash(key);
item* delPtr; //Where I am allowed to create pointers with
item* P1; //no issues
item* P2;
if(HT[index]->x == "")
{
cout << key << " was not found in the hash table" << endl;
}
else if ( HT[index]->x == key && HT[index]->next == NULL)
{
HT[index]->x = "";
cout << key << " was removed from the hash table" << endl;
}
else if(HT[index]->x == key)
{
delPtr = HT[index];
HT[index] = HT[index]->next;
delete delPtr;
cout << key << " was removed from the hash table" << endl;
}
else
{
P1 = HT[index]->next;
P2 = HT[index];
while(P1 != NULL && P1->x != key)
{
P2 = P1;
P1 = P1->next;
}
if(P1 == NULL)
{
cout << key << " was not found in the hash table" << endl;
}
else
{
delPtr = P1;
P1 = P1->next;
P2->next = P1;
delete delPtr;
cout << key << " was removed from the hash table" << endl;
}
}
}
I've tried creating the pointer in the .h file like this:
template<class T>
class DHT1 : public HashTable<T>
{
protected:
int hash(T key);
int collision(T key, int &value);
struct item {
T x;
item* next;
item* temp; // Added declaration
};
item* HT[TABLESIZE];
public:
DHT1();
void printGrid();
};
But that still gives me declaration issues
Are there different methods I should be using when implementing my search function such as any extra parameters in the function call? Or maybe I am just not getting the logic down right?
Thank you for any responses!
You declared item as a std::string, and then you use item in the same scope as a type.
string item; // <-- declaring as string
item* temp = HT[index]; // <-- Compiler doesn't know what to do with this line except to give an error.
The simplest solution is to name your std::string variable something else other than item.

C++ 'this' pointer usage inside class method

I'm porting a binary tree implementation from C to C++, converting it to a class in the process.
Sorry in advance for the C way of handling most things.
The attributes consists of
T data;
node<T> *left, *right;
I'm trying to make changes to the root node through
node<T>* current = this; // points to root node
node<T> newnode = node<T>(5); // just a test value
current->left = &newnode;
cout << "current->left: " << current->left << " value: " << current->left->data << endl;
cout << "this->left: " << " value: " << this->left->data << endl;
In my mind, those two prints should print exactly the same thing, since current and this both point to the same object, but the output I got is clearly different
current->left: 0x7fffffffddb0 value: 5
this->left: 0x7fffffffddb0 value: -139656192
So they point to the same left object, but that object holds different values when viewed differently, what gives?
Additoinal Info
Declaration
template <typename T>
class node {
public:
T data;
node<T> *left, *right;
void insert(T data);
int remove(T target); // returns success or not
node<T>* find(T target);
void print(int mode); // need overloading since can't use 'this' as default var
void print(int mode, node<T>* root);
private:
node<T>* node_new(T data);
void node_find(T key, node<T>*** target_node_address_handle);
void node_delete(node<T>** target_address);
};
Constructor
template <typename T>
node<T>::node(T rootdata) {
data = rootdata;
left = NULL;
right = NULL;
}
Find method shared by insert and delete
template <typename T>
void node<T>::node_find(T key, node<T>*** target_node_address_handle) {
node<T>* current = this;
while(current) {
if (typeid(key) == typeid(current->data)) {
if (key == current->data) break;
else if (key < current->data) current = current->left;
else current = current->right;
}
}
// if loop exited without breaking, will insert into empty NULL position
*target_node_address_handle = &current;
}
My insert doesn't work, but I'm not sure if that's a problem in node_find or node_insert
template <typename T>
void node<T>::insert(T data) {
node<T>** target_node_address;
node_find(data, &target_node_address);
// target_node_address should now point to one of root's decedents
if (!(*target_node_address)) // nothing at target node as expected
*target_node_address = node_new(data);
// node_new returns pointer to node
}
Edit
Copy constructor
template <typename T>
node<T>::node(const node<T>& anothernode) {
data = anothernode.data;
if(anothernode.left) *left = *anothernode.left;
else left = NULL;
if(anothernode.right) *right = *anothernode.right;
else right = NULL;
}
Destructor (both added in declaration)
template <typename T>
node<T>::~node(void) {
left = NULL;
right = NULL;
}
Interesting thing is that it compiled fine before I explicitly added these in...
Problem solved with new node and insert changed to:
template <typename T>
node<T>* node<T>::node_new(T data) {
node<T>* newnode = new node<T>(data);
return newnode;
}
template <typename T>
void node<T>::node_find(T key, node<T>*** target_node_address_handle) {
// find node matched by key, or NULL pointer in correct location
// give node pointer address back
node<T>* root = this;
node<T>** target_address = &root;
while(*target_address) {
node<T>* current = *target_address;
if(typeid(key) == typeid(current->data)) {
// assume comparison operator exists
if(key == current->data)
break;
else if(key < current->data)
target_address = &current->left;
else
target_address = &current->right;
}
}
// if loop exited without breaking, will insert into an empty NULL position
// else loop exited by matching/breaking, will delete non-NULL node
*target_node_address_handle = target_address;
}
Problem was I was giving &current back to *target_node_address_handle, which would be an address to a pointer to NULL, rather than a pointer to a pointer to NULL, which I could change.

Linked list problem with constructor and destructor

Hi
I have some issue regarding constructor and destructor. I have list class, which has two inner classes, one private class for the list nodes, and one public iterator class.
Now for the issue, I have written a non-member print function which uses the inner iterator class. When i use this non-member function it will end calling the destructor for the iterator. It doesn't end here though because for some reason it will also call for the list class's destructor. Which causes some problem when I want to print the list content again.
I don't understand why it call the list class destructor as well and wonder if someone kindly can tell me that, and how I should fix it.
I have attached all the code related to the problem
Main
#include <iostream>
#include "sorted_list.h"
#include "iterator.h"
using namespace std;
void list_print(ostream& os, sorted_list list)
{
sorted_list::iteratorn it(&list);
while( ! it.iterator_end())
{
os << "key = " << setw(3) << it.iterator_get_key() << ", "
<< "value = " << setw(5) << it.iterator_get_value() << endl;
it.iterator_next();
}
os << endl;
}
int main()
{
sorted_list a;
a.insert(4,4);
a.insert(5,5);
list_print(cout,a);
list_print(cout,a);
}
sorted_list.cc
#include "sorted_list.h"
sorted_list::sorted_list()
{
cout << "construct sorted_list" << endl;
this->first = 0;
}
sorted_list::~sorted_list()
{
cout << "destruct sorted_list" << endl;
destroy(this->first);
}
void sorted_list::destroy(list_link* item)
{
cout << "destroy list_link" << endl;
if(item)
{
destroy(item->next);
delete item;
}
}
void sorted_list::insert(int key, double value)
{
list_link *curr;
list_link *prev = 0;
curr = first;
while(curr)
{
if(value < curr->value)
break;
prev = curr;
curr = curr->next;
}
if(this->first == 0 || prev == 0) //if empty or add first
{
//first = create(key, value, this->first);
first = new list_link(key, value, this->first);
}
else if(curr == 0)
{
//prev->next = create(key, value, 0);
prev->next = new list_link(key, value, 0);
}
else
{
//prev->next = create(key, value, curr);
prev->next = new list_link(key, value, curr);
}
}
void sorted_list::remove(my_key_type key)
{
list_link *curr = first;;
list_link *prev = 0;
while(curr)
{
if(curr->key == key)
{
list_link *remove;
if(prev == 0)
{
first = curr->next;
delete curr;
curr = first;
}
else
{
remove = curr;
curr = curr->next;
prev->next = curr;
delete remove;
}
continue;
}
prev = curr;
curr = curr->next;
}
}
sorted_list::list_link* sorted_list::clone(list_link* item)
{
list_link* copyItem= new list_link(item->key,item->value,0);
if(item->next!= 0)
copyItem->next=clone(item->next);
return copyItem;
// ADD YOUR CODE HERE ( 4 well formatted lines in reference solution )
}
void sorted_list::copy(sorted_list* my_this_destination)
{
if (my_this_destination->first == 0) // copy if empty
{
cout << "Copy" << endl;
//list_destroy(my_this_destination);
my_this_destination->first = clone(first);
}
}
double sorted_list::find(int key)
{
list_link *travel = this->first;
while(travel)
{
cout << travel->key << "==" << key << endl;
if(travel->key == key)
return travel->key;
travel = travel->next;
}
return -1;
}
int sorted_list::size()
{
list_link *travel = this->first;
int i = 0;
while( travel )
{
travel = travel->next;
i++;
}
return i;
}
sorted_list.h
#ifndef _SORTED_LIST_H_
#define _SORTED_LIST_H_
#include <iostream>
#include <iomanip>
using namespace std;
typedef int my_key_type;
typedef double my_value_type;
class sorted_list
{
public:
sorted_list();
~sorted_list();
void insert(int key, double value);
void remove(my_key_type key);
void copy(sorted_list* my_this_destination);
void destroy();
void init(struct my_list* my_this);
void print();
void print2();
double find(int key);
int size();
private:
class list_link // An inner class inside sorted_list
{
public:
list_link (my_key_type key, my_value_type value, list_link* next = 0);
~list_link();
my_key_type key;
my_value_type value;
list_link *next;
};
list_link* first;
list_link* clone(list_link* item);
void destroy(list_link* item);
// More declarations
public:
class iteratorn
{
public:
iteratorn();
~iteratorn();
iteratorn(sorted_list *item);
list_link* list_begin();
bool iterator_end();
void iterator_next();
int iterator_get_key();
double iterator_get_value();
private:
sorted_list::list_link* current;
};
};
#endif
iteratorn.cc
#include "iterator.h"
#include "sorted_list.h"
sorted_list::iteratorn::iteratorn()
{
}
sorted_list::iteratorn::iteratorn(sorted_list *list)
{
cout << "construct iteratorn" << endl;
this->current = list->first;
}
sorted_list::iteratorn::~iteratorn()
{
cout << "destruct iteratorn" << endl;
}
sorted_list::list_link* sorted_list::iteratorn::list_begin()
{
return current;
}
void sorted_list::iteratorn::iterator_next()
{
current = current->next;
}
int sorted_list::iteratorn::iterator_get_key()
{
return current->key;
}
double sorted_list::iteratorn::iterator_get_value()
{
return current->value;
}
list_link.cc
#include "sorted_list.h"
sorted_list::list_link::list_link(my_key_type key, my_value_type value, list_link* next)
{
this->key = key;
this->value = value;
this->next = next;
}
sorted_list::list_link::~list_link()
{
cout << "list_link destructor" << endl;
}
Your function void list_print(ostream& os, sorted_list list) takes a sorted_list parameter by copy. A quick and dirty fix (that you should do anyways for performance reasons) is the following:
void list_print(ostream& os, const sorted_list& list)
Now, your iteratornclass takes a mutable list, so this won't work as you expect. You will have quite a few methods to change to make this work.
In any case, your real problem is the lack of a proper copy-constructor. Right now, when you "copy" a list, both end up sharing the same elements, but your destructor is written as if each list owns it's own nodes. Define a proper copy operation and it will solve your problem.
More elaborate help on how to solve the problem: (untested)
Change signature:
void list_print(ostream& os, const sorted_list& list);
Declare + define copy constructor:
sorted_list::sorted_list (const sorted_list& other);
Change iteratorn interface to support a const sorted_list:
class sorted_list::iteratorn
{
public:
iteratorn();
~iteratorn();
iteratorn(const sorted_list& list);
const list_link* list_begin() const;
bool iterator_end() const;
void iterator_next();
int iterator_get_key() const;
double iterator_get_value() const;
private:
// You *should* make this `const` but it is not required.
sorted_list::list_link* current;
};
As you can see, the changes are rather minimal, but need to be applied in various places.
const + non-const iterators:
I applied changes here based on the fact that your iteratorn was currently only defining read-only operations on your sorted_list. If you want to support write access to allow changing the value stored in list nodes (never allow changing the key or you won't have a sorted list anymore), you should define two iterator classes. See the STL iterator interface for more details.
You're copying the list by value, so the local copy in list_print() destructs at end of scope. Pass it by const-reference instead.
This in turn means you will have to change your sorted_list to support working with const lists. In particular you need to have a function that returns a const iterator pointing to the beginning of the list:
sorted_list::const_iteratorn begin() const
{
// returns a const_iteratorn pointing at the beginning of this list
}
Notice you need a new kind of iterator: a const_iteratorn, which promises it won't change the list.
Then, inside print_list() initialize a const_iteratorn with the start iterator that sorted_list returns, by copy:
sorted_list::const_iteratorn s(list.begin());
Finally create a second iterator instance that initializes with an end iterator coming from a member function of sorted_list, similar to the begin() function. This will maintain the const-correctness in print_list().
sorted_list::const_iteratorn e(list.end());
while( s != e ) { // two iterators should be able to compare
// ...
s.iterator_next(); // consider ++s
}
Also, as André mentioned, the fact you don't have a proper copy-constructor and assignment operator is a severe issue. Make sure that copying a sorted_list means copying all its elements, so that the new object owns its own list of elements. Do recall the Rule of Three.