2016-10-19 10 views
1

リンクリスト内のノードを削除した後、テールローポインタを新しいテールに更新する方法を解明しようとしています。私は、次の実装を持って戻ってからノードを除去するためC++ - リンクされたリスト内のunique_ptrノードへの生ポインタの割り当て

std::unique_ptr<Node> head ; 
    Node* tail ; 

と私の機能のように頭と尾を定義した

(宿題です)。

int Deque::remove_back(){ 
if (empty()) {throw std::runtime_error(std::string("Empty"));}; 

std::unique_ptr<Node> old; 

Node* p = head.get(); 

int return_value = tail->val; 

while (p->next != tail) 
{p = p->next)} 

old = move(tail); 
tail = p; 

return return_value; 
} 

したがって、tailはNode型の生ポインタです。 PはNode型の生ポインタです。

HeadはNode型の一意のポインタです。

私は頭

P = P - >次へと、P = head.get()

ので、今のpポイントを設定していますが、私のノードを停止反復処理する必要があります。

問題がp->next != tail

P->次は何Pの次のノードへのポインタであることです。

ノードへのポインタを、ノード(テール)タイプの生ポインタと等しくなるように設定しようとしています。

私はこれを行うことはできません。

私はそれがp-であると信じていますが、私はそれを宣言したものを観察するのではなく、所有するポインタに変更していません。

エラー:

Deque.cpp|68|error: no match for 'operator!=' (operand types are 'std::unique_ptr<Node>' and 'Node*')| 

Deque.cpp|69|error: cannot convert 'std::unique_ptr<Node>' to 'Node*' in assignment| 

Deque.cpp|71|error: no match for 'operator=' (operand types are 'std::unique_ptr<Node>' and 'std::remove_reference<Node*&>::type {aka Node*}')| 
+0

あなたは 'tail'を使用する必要がありますか?それはまったく助けにならない。 – Slava

+0

残念ながら、 : – TigerCode

+0

シングルリンクリストの 'tail'は、リストの最後にあるファーストインサートにのみ有効ですが、リストの最後に速いリムーバブルに使うことはできないので、無駄です。 –

答えて

4

エラーメッセージがNode::nextstd::unique_ptr<Node>であることを示唆しています。 std::unique_ptrを生ポインタに直接比較/割り当てすることはできません。あなたが代わりにstd::unique_ptr::get()メソッドを使用する必要があります。リストには、その中に1つだけのノード(head == tail)を持っているとき

while (p->next.get() != tail) { 
    p = p->next.get(); 
} 

をまた、あなたのループは考慮していません。 p->nextは、2回目の繰り返しとクラッシュ時にnullptrになります。リストの最後のノードを削除するので、headnullptrにリセットする必要があります。いずれにしても、を新しいtailとして割り当てる場合は、p->nextnullptrにリセットする必要があります。したがって、古いノードを指していないようにしてください。言われて、それがリンクリストの実装でstd::unique_ptrを使用してトリッキーなことができることを

int Deque::remove_back(){ 
    if (empty()) { 
     throw std::runtime_error("Empty"); 
    } 

    int return_value = tail->val; 

    if (!head->next) { 
     head = nullptr; // or: head.reset(); 
     tail = nullptr; 
    } 
    else { 
     Node* p = head.get(); 
     Node *prev = p; 
     while (p->next->next) { 
      p = p->next.get(); 
      prev = p; 
     } 
     tail = prev; 
     tail->next = nullptr; // or: tail->next.reset(); 
    } 

    return return_value; 
} 

はこれを試してみてください。ノードを自動的に破棄したい場合は、生ポインタを使用して、それ自体が破棄されたときにノードを破壊するクラス内のリストをラップしてから、remove_back()が削除されるノードを破棄することができます。

STLには、すでにstd::list(ダブルリンク)とstd::forward_list(シングルリンク)のクラスが用意されています。手動リストの実装の代わりにそれらを使用する必要があります。

+0

for宿題のように、スマートポインタを使用するための実装の理由と実装方法を検討するための多くの制限があります。 – TigerCode

+1

"nullptrの隣のp->をリセットしていません" OPがrawを割り当てることができないことを認識すると修正されます'std :: unique_ptr'へのポインタ' std :: unique_ptr'を正しく使うと意味があると思います。 – Slava

+0

'std :: unique_ptr old;と' Node * Tail'は互いに移動できません – TigerCode

1

要素が1つしかない場合、関数に問題があります。条件が必要です(コードが重複している)か、少し複雑にしてください:

int Deque::remove_back(){ 
    if (empty()) {throw std::runtime_error(std::string("Empty"));}; 

    Node *newtail = nullptr; 
    std::unique_ptr<Node> *curr = &head; 
    while(curr->get() != tail) { 
     newtail = curr->get(); 
     curr = &(*curr)->next; 
    } 

    tail = newtail; 
    std::unique_ptr<Node> tmp = std::move(*curr); 

    return tmp->val; 
} 
+0

私はあなたのループが私よりも好きです。 –

関連する問題