2016-07-14 5 views
1

リンクリストの概念を使ってListクラスを作ろうとしていて、もともとC++標準のnewキーワードを使用していましたが、C++ 11 std::shared_ptr 。しかし、スマートポインタを使用しているときにプログラムが正常に機能するようにすることはできません。ここでは変更前のコードのいくつかのビットは、次のとおりです。C++設定ポインタshared_ptrと等しく

class List 
{ 
public: 
    void push_back(...) { 
     Node *temp = new Node; 
     ... 
     if (!head) { 
      head = temp; 
      return; 
     } 
     else { 
      Node *last = head; 
      ... 
      last->next = temp; 
     } 
    } 
    ... 

private: 
    Node *head = nullptr; 
}; 

そして、ここではそれを変更して次のようになります。

class List 
{ 
public: 
    void push_back(...) { 
     std::shared_ptr<Node> temp(new Node); 
     ... 
     if (!head) { 
      head = temp.get(); 
      return; 
     } 
     else { 
      Node *last = head; 
      ... 
      last->next = temp.get(); 
     } 
    } 
    ... 

private: 
    Node *head = nullptr; // don't need this to be a smart ptr 
}; 

私は問題のように感じるheadlastが動的に割り当てられていないということかもしれませんおそらく彼らはshared_ptrで作業する必要がありますが、わかりません。私は間違って何をしているのですか?どうすれば修正できますか?私は私の問題を解決するものを見つけることができないので、これは複製ではないことを本当に願っています。ありがとう。

編集:

struct Node{ 
    int data; 
    Node* next; 
}; 
+0

「Node」の定義に問題があると思います。 – Assimilater

+0

動的に割り当てられる「temp」ノードが必要なようです。そうでなければ、プログラムは動作しません。標準の 'new'ではなく' shared_ptr'で動的に割り当てることを考えてください。 'Node'構造体を投稿することができれば助かります。 –

+0

はい、 'Node'構造体を投稿してください:) – Assimilater

答えて

1

あなたの主な問題は、あなたがそれをすべての方法を使用するのが最善、shared_ptrを使用するつもりならばということである。 ここNode構造体です。生のものの代わりにnextshared_ptrにします。ボンネットの下に何std::shared_ptr

struct Node { 
    int data; 
    std::shared_ptr<Node> next; 
} 

は、ポインタにあるどのように多くの参照のカウントを保持します。 コピーコンストラクタまたはoperator=を使用すると、参照カウントが増加します。インスタンスがスコープから外れてデストラクタが呼び出されると(または別のポインタにoperator=を渡すと)、参照カウントは減少します。カウントがゼロのとき、ポインタは破棄されます。

// pass by value invokes copy constructor (refcount + 1) 
void myFunc(std::shared_ptr<MyClass> var) { 

    // Code using var 

} // end of function invokes destructor (refcount - 1) 

void run() { 
    std::shared_ptr<MyClass> ptr(new MyClass); // refcount = 1 
    myFunc(ptr); // refcount = 2 
    // After myFunc returns refcount = 1 

} 
int main() { 
    run(); // refcount = 1 
    // After run returns, refcount = 0 and the pointer is deleted 
} 

get()を使用することによって、あなたは関係なく、そのポインタが周囲にあるかどうかの、ある時点で削除される場合があり、メモリへのポインタを紹介します。これは、生ポインタがメモリを指しているので、セグフォルトにつながる可能性があります。shared_ptrが削除されました。

get()は参照カウントに影響しないためです。どうした? shared_ptrではありません。そのため、クラス定義では、そのクラスで何を行うのか、それが削除されるのかを知る方法がありません。 get()が参照カウントを増加させた場合、後でそれを減らすものはなく、メモリは決して解放されません。それはメモリリークです!最初の場所でstd::shared_ptrを持っている

+0

ああ、私が参照してください。私はスマートポインタ(必ずしもあなたのように動的に割り当てられているわけではありません)とポインタのすべての出現を置き換え、彼の問題を修正しました。ありがとう。 –

+0

実際には、この質問に触発されて、私は今日彼らがリンクリスト*自体*(皮肉を愛している)として実装することができることを学んだ。参照してください:http://stackoverflow.com/questions/725142/how-does-a-reference-counting-smart-pointers-reference-counting-work – Assimilater

+0

ねえ、それはかなり良いです! –

4

理由はstd::shared_ptr持つポインタの完全かつ完全な所有権を取得し、ポインタへの最後の参照がなくなったら、deletestd::shared_ptrの責任、それを作ることです。それはstd::shared_ptrのすべてです。

これは、いったんポインタがstd::shared_ptrに配置されると、std::shared_ptrはポインタ管理の完全かつ完全な責任を負うことを意味します。それは完全にそれを所有しています。

したがって、std::shared_ptrにポインタを置くことは意味がありません。その後、すぐにそれを取る:

head = temp.get(); 

get()関数が存在する理由がありますが、これはその一つではありません。

std::shared_ptrを正しく使用するには、すべてがstd::shared_ptrである必要があります。 headstd::shared_ptrする必要があります:

std::shared_ptr<Node> head; // yes, it does need to be a smart ptr 

なぜそれがstd::shared_ptrする必要がありますか。この関数が返すとき

std::shared_ptr<Node> temp(new Node); 

具体的には、このtempスマートポインタは、破壊されます:?それはない場合さて、あなたは、これが時に何が起こるかと思いますかさて、このNodeを参照したのは最後のstd::shared_ptrなので、それはうれしくdeleteです。実際にはget()それ以前に入れてheadに入れても問題ありません。だからdeleteノードを指しているheadがあります。喜びが続く。

これはすべてがstd::shared_ptrである必要があるためです。 headだけでなく、Nodenextのメンバーでもstd::shared_ptrである必要があります。

今、std::shared_ptrが画像に入ったときに再生される循環参照を含む落とし穴があります。しかし、それは別の質問になるでしょう。

+0

偉大な、詳細な答えをありがとう。私は同盟者の反応を彼の握りこぶしとして受け入れて問題を解決しましたが、私は本当にあなたの答えが好きです:) –

+0

@ArchieGertsman私はこの答えが出てきたのでこの種の情報で私の答えを編集していました。これは、フードの下で何が起こっているのかをもう少し理解するのに役立ちます – Assimilater

関連する問題