c++ - Unable to move temporary object into the *this object -
while trying create binary search tree (bst) using c++11 hit snag. can't extract created bst out of function created. function reads data file (in case number on each line) , builds bst those. building part in loop works correctly. problem can't temporary object moved want be.
zooming in on problem think, see edit 3.
more context: bst<t>
class derives publicly std::unique_ptr<bstknoop<t>>
bst<t>
inherits 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 body of bst<t> class declaration`
a bstknoop<t>
data structure 3 fields 1 t object hold node data 2 bst<t>
objects left , right (each child tree in own right)
the goal move newly created bst calling object. idea in main can call bst<int> tree; tree.lees(ifs);
(with ifs
open input filestream) , tree holds 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); /* not work */ /* *this = move(temptree); not work either*/ return is; }
i have tried return bst<t>
function , moving result in main. didn't work either.
the program crashes @ runtime unknown signal.
side note: i'm unsure why bst<t> temptree(new bstknoop<t>());
works in regard templating. construction works because bst<t>
inherits constructors unique_ptr<bstknoop<t>>
edit 1: declaration of 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 move constructor , move assignment operator. i've made sure retain default constructor using bst<t>()=default;
i'm confused though: bst class doesn't have members have implement own move constr / operator.
however, bst has inherited unique_ptr<bstknoop<t>>
so implicitly, must hold member of type. suppose want keep inheritance, there neat way make work? is true can't (or perhaps shouldn't) implement copy constr / operator deleted 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: own move constr / operator, temptree no longer gets filled properly. below code add used build tree. if omit own move constr / operator, works. need operation works this->get()->links = move(tmp)
. types this->get()->links => bst<t>
tmp => bst<t>
how come works? operation need, why can't use similar *this = move(temptree)
writing 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); } } }
okay, made stupidest mistake. there nothing wrong inheritance , accompanying move semantics. used data_set_length preprocessor directive inside istream& bst<t>::lees(istream& is)
function. while final dataset hold million items. dataset testing purposes holds 12. forgot change value of data_set_length stoi(lijn)
crashed.
for interested in solution:
notes
- you don't need write code make work.
- it possible write
bst<t>& operator=(bstknoopptr<t>&&);
, works. without explicitly writing own works. - the bst class has no fields of pointer type don't trouble unique_ptr not having virtual destructor
final question (perhaps can comment): inherited operator operator=(bstknoopptr<t>&&)
, signature in bst<t>
? in regards return type (if it's member of bst<t>
type return?).
** tldr: why can rely on inherited move operator / move constructors of unique_ptr<bstknoop<t>>
? **
bst.h
#define data_set_length 12 using namespace std; template <class t> class bst; template <class t> class bstknoop; template<class t> using bstknoopptr=std::unique_ptr<bstknoop<t>>; template <class t> class bst:public bstknoopptr<t>{ using bstknoopptr<t>::bstknoopptr; public: bst<t>& operator=(bst<t>&&) = default; bst<t>(bst<t>&&) = default; bst<t>()=default; //bst<t>& operator=(bstknoopptr<t>&&); 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&); //schrijf schrijft uit in een vorm die min of meer menselijk leesbaar ostream& schrijf(ostream&); ostream& schrijfknoop(ostream&) const; int aantalsleutels() const; istream& lees(istream&); //schrijflevelorder schrijft uit in een vorm die door lees(...) kan gelezen worden. ostream& schrijflevelorder(ostream& os) const; private: }; template <class t> class bstknoop{ friend class bst<t>; public: bstknoop() {} explicit bstknoop(t _sl) : sl(_sl) {} private: t sl; bst<t> links,rechts; }; //template<class t> //bst<t>& bst<t>::operator=(bstknoopptr<t>&& other){ // cout<<"called bst<t> move bstknoopptr r-value ref argument"<<endl; // (*this).bstknoopptr<t>::operator=(move(other)); // return *this; //} 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 { //bstknoopptr<t> tmp(new bstknoop<t>(value)); if used own bst<t>& bst<t>::operator=(bstknoopptr<t>&& other) bst<t> tmp(new bstknoop<t>(value)); this->get()->links = move(tmp); } } else{ if(this->get()->rechts != nullptr){ this->get()->rechts.add(value); } else{ //bstknoopptr<t> tmp(new bstknoop<t>(value)); if used own bst<t>& bst<t>::operator=(bstknoopptr<t>&& other) bst<t> tmp(new bstknoop<t>(value)); this->get()->rechts = move(tmp); } } } 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 = move(temptree); return is; }
main.cpp
int main(){ ifstream ifs; ifs.open("c.dat"); if(ifs.is_open()){ bst<int> tree; tree.lees(ifs); tree.schrijfknoop(cout); } else { cerr<<"failed open file"<<endl; return -1; } }
Comments
Post a Comment