无法将临时对象移动到*此对象

时间:2017-08-14 20:01:59

标签: c++ c++11 move-semantics unique-ptr

在尝试使用C ++ 11创建二进制搜索树(BST)时,我遇到了麻烦。 我无法从创建它的函数中提取正确创建的BST。 该函数从文件中读取数据(在这种情况下,每行只是一个数字)并从中构建BST。循环中的构建部分正常工作。 问题是我无法将临时对象移动到我想要的位置。

放大我认为的问题,请参阅编辑3.

更多背景信息: BST<T>是一个从std::unique_ptr<BSTknoop<T>>公开派生的类 BST<T>还继承了unique_ptr<BSTknoop<T>>

的构造函数
template<class T>
using BSTknoopptr=std::unique_ptr<BSTknoop<T>>; // alias template

using BSTknoopptr<T>::BSTknoopptr; // in the body of the BST<T> class declaration`

BSTknoop<T>是一个包含3个字段的数据结构 一个T对象来保存节点数据 左右两个BST<T>个对象(每个孩子本身就是一棵树)

目标是将我新创建的BST移动到调用对象中。我的想法是,在main中你可以调用BST<int> tree; tree.lees(ifs);ifs一个打开的输入文件流),然后树会保存正确填充的BST。

功能:

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;
}

我还尝试从函数返回BST<T>并将结果移到main中。这也不起作用。

程序在运行时因未知信号而崩溃。

旁注:我不确定为什么BST<T> temptree(new BSTknoop<T>());在模板方面有效。由于BST<T>继承了unique_ptr<BSTknoop<T>>

的构造函数,因此构造工作正常

编辑1:BST<T>类的声明:

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:
};

BSTknoop<T>类的声明:

template <class T>
class BSTknoop{
    friend class BST<T>;
public:
    BSTknoop() {}
    explicit BSTknoop(T _sl) : sl(_sl) {}
private:
    T sl;
    BST<T> links,rechts;
};

编辑2:我已经写了一个移动构造函数并移动赋值运算符。我已确保使用BST<T>()=default;保留默认构造函数但我很困惑:BST类没有任何成员我必须实现自己的移动构造/操作员。
但是,BST从unique_ptr<BSTknoop<T>>继承了如此含蓄,它必须拥有该类型的成员。假设我想保留继承,有没有任何巧妙的方法来使这项工作? 我也不能(或者不应该)实现复制构造/操作符,因为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;
}

编辑3:使用我自己的移动constr / operator,temptree不再被正确填充。下面是我的add代码,用于构建树。如果我省略了我自己的移动constr / operator,那么这是有效的。我需要的是一个像this->get()->links = move(tmp)一样的操作。 类型this->get()->links => BST<T>      tmp => BST<T> 怎么运作?它完成了我需要的操作,为什么我不能通过自己编写操作来使用与*this = move(temptree)类似的东西。

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);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

好吧,我犯了最愚蠢的错误。继承和伴随的移动语义没有任何问题。我在istream& BST<T>::lees(istream& is)函数中使用了DATA_SET_LENGTH预处理程序指令。虽然我的最终数据集将包含一百万个项目。我用于测试目的的数据集只有12个。我忘了更改DATA_SET_LENGTH的值,因此stoi(lijn)崩溃了。

对于对解决方案感兴趣的任何人:

备注

  • 您不需要编写太多代码来完成这项工作。
  • 可以自己编写BST<T>& operator=(BSTknoopptr<T>&&);并且它有效。然而,即使没有明确地编写自己的,它也可以。
  • BST类没有指针类型的字段,因此我们不会遇到没有虚拟析构函数的unique_ptr

最后的问题(也许有人可以评论): 继承的运算符operator=(BSTknoopptr<T>&&),它的签名在BST<T>中是什么样的?主要是关于返回类型(如果它现在是BST<T>的成员,它返回什么类型?)。

** TLDR:为什么我可以依赖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 is
    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 with 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 with my 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 with my 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 to open file"<<endl;
        return -1;
    }
}