2011-10-09 70 views
2

我正在寫一個樹狀的容器,其中每個「節點」與分支機構/子樹列表,目前我的頭看起來像:移動語義和引用語義

class _tree { 
public: 
    typedef _tree* tree_ptr; 
    typedef std::list<_tree> _subTreeTy; 

    explicit _tree(const _ValTy& v, const _NameTy& n); //create a new tree 
    _tree(const _ValTy& v, const _NameTy& n, tree_ptr _root); 
     //create a new tree and add it as branch to "_root". 

    ~_tree(); 

    void add_branch(const _tree& branch); //add by copy 
    void add_branch(_tree&& branch); //add by move 
private: 
    _subTreeTy subtrees; 
    _ValTy value; 
    _NameTy name; 
}; 


_tree::_tree(const _ValTy& v, const _NameTy& n, tree_ptr _root) 
    : root(_root), 
    value(v), 
    name(n) 
{ 
    _root->add_branch(*this); //not rvalue(???) 
} 

現在第二個構造函數創建內_root一棵樹 - 但是如何與調用該作品(忽略私有違規):

_tree Base(0,"base"); 
_tree Branch(1, "branch", &Base); 
Base.subtrees.begin()->value = 8; 
std::cout << Branch.value; 

我將如何讓這個Branch & *Base.subtrees.begin()指同一個節點?或者我應該走另一條路。使用add_branch()來創建分支/子樹?

+5

以下劃線開頭並帶有大寫字母的標識符被保留用於實現。而且看起來很醜。 –

+0

它與移動語義有什麼關係? – crazyjul

+0

我冒昧地改變了標題,因爲它沒有很多信息(還有其他一些小的變化)。希望這仍能傳達你的問題。 –

回答

3

移動語義是關於移動一個對象的內部,而不是對象(作爲一個類型化的內存)本身。最好用值和不變量來考慮它,因爲即使考慮到移動,C++仍然具有值語義。這意味着:

std::unique_ptr<int> first(new int); 
// invariant: '*this is either null or pointing to an object' 
// current value: first is pointing to some int 
assert(first != nullptr); 

// move construct from first 
std::unique_ptr<int> second(std::move(first)); 

// first and second are separate objects! 
assert(&first != &second); 

// New values, invariants still in place 
assert(first == nullptr); 
assert(second != nullptr); 

// this doesn't affect first since it's a separate object 
second.reset(new int); 

換句話說,當你可以通過做std::move(*this)表達*this轉換爲右值你想,不能因爲std::list<_tree>現在取得的成績使用值語義和_tree值語義本身。 *Base.subtrees.begin()是與Branch不同的對象,因爲前者的修改不會影響後者。

如果這就是你想要的(或需要)切換到引用語義,例如通過使用std::shared_ptr<_tree>std::enable_shared_from_this(然後在構造函數中使用_root->add_branch(shared_from_this()))。我不會推薦它,但這可能會變得混亂。在我看來,價值語義是非常可取的。


值語義的,用你的樹看起來是這樣:

_tree Base(0, "base"); 
auto& Branch = Base.addBranch(1, "branch"); 

也就是說,addBranch返回新建節點的引用。灑在上面有所動作語義:

_tree Base(0, "base"); 
_tree Tree(1, "branch); // construct a node not connected to Base 
auto& Branch = Base.addBranch(std::move(Tree)); 
// The node we used to construct the branch is a separate object 
assert(&Tree != &Branch); 

嚴格地說,如果_tree是可複製移動語義是沒有必要的,雖然,Base.addBranch(Tree);將工作太。