While trying to create a Binary Search Tree (BST) using C++11 I hit a snag. I can't extract a properly created BST out of the function where it is created. The function reads data from a file (in this case just a number on each line) and builds a BST from those. The building part in the loop works correctly. The problem is I can't get the temporary object moved where I want it to be.
Zooming in on the problem I think, see edit 3.
More context:
BST<T>
is a class that derives publicly from std::unique_ptr<BSTknoop<T>>
BST<T>
also inherits the constructors of unique_ptr<BSTknoop<T>>
with
template<class T>
using BSTknoopptr=std::unique_ptr<BSTknoop<T>>; // alias template
and
using BSTknoopptr<T>::BSTknoopptr; // in the body of the BST<T> class declaration`
A BSTknoop<T>
is a data structure with 3 fields
one T object to hold the node data
two BST<T>
objects left and right (each child is a tree in its own right)
the goal is to move my newly created BST into the calling object. The idea is that in main you can call BST<int> tree; tree.lees(ifs);
(with ifs
an open input filestream) and tree holds the properly filled BST afterwards.
The function:
template<class T>
istream& BST<T>::lees(istream& is){
string lijn;
T knoopwaarde;
getline(is,lijn);
knoopwaarde = stoi(lijn);
BST<T> temptree(new BSTknoop<T>());
temptree->sl = knoopwaarde;
for(int i=1; i<DATA_SET_LENGTH ; i++){
getline(is,lijn);
knoopwaarde=stoi(lijn);
temptree.add(knoopwaarde);
cout<<temptree;
}
this->swap(temptree); /* This does not work */
/* *this = move(temptree); this does not work either*/
return is;
}
I have also tried to return a BST<T>
from the function and moving that result in the main. That didn't work either.
The program crashes at runtime with an unknown signal.
Side note: I'm unsure as to why BST<T> temptree(new BSTknoop<T>());
works in regard to the templating. The construction works because BST<T>
inherits the constructors for unique_ptr<BSTknoop<T>>
edit 1: the declaration of the BST<T>
class:
template <class T>
class BST:public BSTknoopptr<T>{
using BSTknoopptr<T>::BSTknoopptr;
public:
friend istream& operator>>(istream& is, BST<T>& bb){
return bb.lees(is);
}
friend ostream& operator<<(ostream& os, const BST<T>& bb){
//return bb.schrijflevelorder(os);
return bb.schrijfKnoop(os);
}
void add(const T&);
ostream& schrijf(ostream&);
ostream& schrijfKnoop(ostream&) const;
int aantalSleutels() const;
istream& lees(istream&);
ostream& schrijflevelorder(ostream& os) const;
private:
};
the declaration of theBSTknoop<T>
class:
template <class T>
class BSTknoop{
friend class BST<T>;
public:
BSTknoop() {}
explicit BSTknoop(T _sl) : sl(_sl) {}
private:
T sl;
BST<T> links,rechts;
};
edit 2: I've written a move constructor and move assignment operator. I've made sure to retain the default constructor as well using BST<T>()=default;
I'm confused though: the BST class doesn't have any members for which I would have to implement my own move constr / operator.
However, BST has inherited from unique_ptr<BSTknoop<T>>
so implicitly, it must hold a member of that type. Suppose I want to keep the inheritance, is there any neat way to make this work?
Is is also true that I can't (or perhaps shouldn't) implement a copy constr / operator as those are deleted for unique_ptr?
template<class T>
BST<T>::BST(BST<T>&& other){
*this = move(other);
}
template<class T>
BST<T>& BST<T>::operator=(BST<T>&& other){
cout<<"called move operator BST"<<endl;
(*this).BSTknoopptr<T>::operator=(move(other));
return *this;
}
edit 3: with my own move constr / operator, the temptree no longer gets filled properly. Below is my code for add which is used to build the tree. If I omit my own move constr / operator, then this works. What I need is an operation that works like this->get()->links = move(tmp)
.
types this->get()->links => BST<T>
tmp => BST<T>
How come this works? It does the operation I need, why can't I use something similar to do *this = move(temptree)
by writing the operation myself.
template<class T>
void BST<T>::add(const T& value){
if(value <= this->get()->sl){
if(this->get()->links != nullptr){
this->get()->links.add(value);
}
else {
BST<T> tmp(new BSTknoop<T>(value));
this->get()->links = move(tmp);
}
}
else{
if(this->get()->rechts != nullptr){
this->get()->rechts.add(value);
}
else{
BST<T> tmp(new BSTknoop<T>(value));
this->get()->rechts = move(tmp);
}
}
}