どのように検出サイクル利用時のshared_ptr
-
13-09-2019 - |
質問
shared_ptrはリファレンスカウンタースマートポインタのブ図書館があります。
この問題を参考計数であることはできないという処理を繰り返す。私はどんな風に思って解決このC++.
くださいませご提案い"を作成するのではありませんサイクル"、"使用weak_ptr".
編集
いることはないと思うだけで使用weak_ptrがある場合から取り寄せた選りすぐりの作成サイクルしない問題です。きものを知ることはできないますが、サイクルをコンパイル時間の場合をshared_ptrs時に行います。
だから、自己の削除答えを使用するweak_ptrしかにさせることはお断り申し上げてそういう答え...
解決
私は、大規模なUMLのグラフを描画し、サイクルを探して比べてはるかに優れた方法を発見していない。
デバッグするには、私はこのように、レジストリに行くインスタンスカウンタを使用します:
template <DWORD id>
class CDbgInstCount
{
public:
#ifdef _DEBUG
CDbgInstCount() { reghelper.Add(id, 1); }
CDbgInstCount(CDbgInstCount const &) { reghelper.Add(id, 1); }
~CDbgInstCount() { reghelper.Add(id, -1); }
#else
#endif
};
私だけの問題のクラスにそれを追加するために定義され、レジストリを見てます。
(IDは、例えばとして与えられた場合は、「XYZ!」の文字列に変換されます。残念ながら、あなたはテンプレートパラメータとして文字列定数を指定することはできません)
他のヒント
shared_ptr
はの所有権の関係を表しています。 weak_ptr
はの意識のを表しています。お互いを所有する複数のオブジェクトを持つことは、あなたが一つ以上を変更することによって解決されるアーキテクチャ、との問題を持っていることを意味し、の自分ののののの意識の中へのの(つまり、weak_ptr
のです)。
示唆weak_ptr
が役に立たないと考えられている理由は、私は得ることはありません。
私はgliblyことでご迷惑が循環参照を破るためにweak_ptrを使用するように言われ、私は循環参照が悪いプログラミングスタイルであることを告げていたときに私自身、私はほとんど怒りを感じて理解します。
あなたのどのように循環参照を見つけるん特にお願いします。真実は、複雑なプロジェクトである基準サイクルがスポットを間接的に困難であるということです。
答えは、循環参照に弱いあなたを残し虚偽の宣言を作るべきではないということです。私は深刻だと私は非常に人気の練習を批判しています - 。やみくもにすべてのためのshared_ptrを使用して
あなたはポインタが所有者であるとの観測者であるそのデザインに明確にする必要があります。
所有者はshared_ptrのを使用してください。
それらのすべてだけでなく、あなたが思うものはサイクルの一部であってもよい。 -オブザーバーはweak_ptrをを使用してください
あなたは、この練習をたどる循環参照が問題を引き起こすことはありませんし、あなたがそれらを心配する必要はありません。 もちろん、あなたがそれらを使用したいときshared_ptrsに、これらすべてのweak_ptrsを変換するために書くためにコードの多くを持っています - 。ブーストは本当に仕事までではありません。
で比較的容易に検出するサイクル
- 設定カウント一largish数、1000(正確なサイズに依存)
- のpionterご興味のあるフォローへのポインターから
- 各ポインタで、減分をカウント
- の場合はカウントがゼロになる前に、終端ポインターチェーン、サイクル
ではないしかし、非常に便利です。なお、一般に解のcycvle問題のための参考カウンポイント-その代替生ごみコレクションスキームのような世代の掃気が誕生するに至りました。
多分boost::weak_ptr
とboost::shared_ptr
の組み合わせ? 記事では、興味があるかもしれます。
検出サイクルで、この記事を参照してください。 >グラフインチ
サイクルを見つけるための一般的な解決策がここで見つけることができます:
リンクされているかどうかをテストするには、ベストアルゴリズムリストには、サイクルを持っている。
これは、リスト内のオブジェクトの構造を知っていることを前提とし、各オブジェクトに含まれるポインタのすべてを追跡することができます。
おそらく必要とされるガベージコレクタなどの手法を用 マークは、掃引.このアルゴリズムは:
- いリストへの参照を持つすべてのメモリブロックに割り当てられます。
- ある時点で開始するガベージコレクタ:
- 最初に、マークのすべてのブロックでもアクセスを使用せずに参照一覧です。
- このリストを消去各項目にできなかった目的では到達できないもうそんなに便利です。
以降のご利用 shared_ptr
他の現存のポインタで届かない場合として考慮されるべきである。員のサイクルです。
実施
以下について述べる非常に素朴例をどのように実施するかについ sweep()
のアルゴリズムまで reset()
すべての残りのポインタのコレクターが所有していた。
このコード店 shared_ptr<Cycle_t>
ポインタ.のクラス Collector
の責任は身体の安全を確保するためのすべてのポインタの削除が sweep()
が実行されます。
#include <vector>
#include <memory>
class Cycle_t;
typedef std::shared_ptr<Cycle_t> Ref_t;
// struct Cycle;
struct Cycle_t {
Ref_t cycle;
Cycle_t() {}
Cycle_t(Ref_t cycle) : cycle(cycle) {}
};
struct collector {
// Note this vector will grow endlessy.
// You should find a way to reuse old links
std::vector<std::weak_ptr<Cycle_t>> memory;
// Allocate a shared pointer keeping
// a weak ref on the memory vector:
inline Ref_t add(Ref_t ref) {
memory.emplace_back(ref);
return ref;
}
inline Ref_t add(Cycle_t value) {
Ref_t ref = std::make_shared<Cycle_t>(value);
return add(ref);
}
inline Ref_t add() {
Ref_t ref = std::make_shared<Cycle_t>();
return add(ref);
}
void sweep() {
// Run a sweep algorithm:
for (auto& ref : memory) {
// If the original shared_ptr still exists:
if (auto ptr = ref.lock()) {
// Reset each pointer contained within it:
ptr->cycle.reset();
// Doing this will trigger a deallocation cascade, since
// the pointer it used to reference will now lose its
// last reference and be deleted by the reference counting
// system.
//
// The `ptr` pointer will not be deletd on the cascade
// because we still have at least the current reference
// to it.
}
// When we leave the loop `ptr` loses its last reference
// and should be deleted.
}
}
};
を利用できますのでこのように:
Collector collector;
int main() {
// Build your shared pointers:
{
// Allocate them using the collector:
Ref_t c1 = collector.add();
Ref_t c2 = collector.add(c1);
// Then create the cycle:
c1.get()->cycle = c2;
// A normal block with no cycles:
Ref_t c3 = collector.add();
}
// In another scope:
{
// Note: if you run sweep an you still have an existing
// reference to one of the pointers in the collector
// you will lose it since it will be reset().
collector.sweep();
}
}
いたしましてValgrindないメモリの漏洩又は"まだ到達可能な"ブロック市場に上場いであろうと期待される。
についてこの実装:
- メモリベクトル成長して延々と本を使用してみてください 一部のメモリ割り当て手法 をしないようにしてください占有する全てのワーキングメモリ。
- という指摘もある必要がない利用
shared_ptr
この作品のようなリファレンスカウンターのGCを実施するためのようなガベージコレクタからのマークは、掃引のアルゴリズムがでの仕事です。 - なかった実施のmark()機能で複雑に例することが可能で、ついてご説明します。
最後に、ご関係(2)このように実装しない例です。CPythonの実施のPython)使用されないようにする方法は混合物のリファレンスカウンターとマークは、掃引が主 歴史的な理由により.
の実施 mark()
機能:
実施のため mark()
機能が必要となりま一部変更
が必要な追加 bool marked;
属性 Cycle_t
, 使用するかどうかのチェックポインタが目印です。
する必要がありまし Collector::mark()
機能するようになります:
void mark(Ref_t root) {
root->marked = true;
// For each other Ref_t stored on root:
for (Ref_t& item : root) {
mark(item);
}
}
そしておきたいの変更 sweep()
機能のマークがポインタが目印ですか reset()
のポインター:
void sweep() {
// Run a sweep algorithm:
for (auto& ref : memory) {
// If it still exists:
if (auto ptr = ref.lock()) {
// And is marked:
if (ptr->marked) {
ptr->marked = false;
} else {
ptr->cycle.reset();
}
}
}
}
また長い説明をしていますが、なんとかこの人がいる。
古い質問に対する回答は、あなたは、リソースが参照される回数をカウントするために助けることが押し付けがましいポインタを試してみることがあります。
#include <cstdlib>
#include <iostream>
#include <boost/intrusive_ptr.hpp>
class some_resource
{
size_t m_counter;
public:
some_resource(void) :
m_counter(0)
{
std::cout << "Resource created" << std::endl;
}
~some_resource(void)
{
std::cout << "Resource destroyed" << std::endl;
}
size_t refcnt(void)
{
return m_counter;
}
void ref(void)
{
m_counter++;
}
void unref(void)
{
m_counter--;
}
};
void
intrusive_ptr_add_ref(some_resource* r)
{
r->ref();
std::cout << "Resource referenced: " << r->refcnt()
<< std::endl;
}
void
intrusive_ptr_release(some_resource* r)
{
r->unref();
std::cout << "Resource unreferenced: " << r->refcnt()
<< std::endl;
if (r->refcnt() == 0)
delete r;
}
int main(void)
{
boost::intrusive_ptr<some_resource> r(new some_resource);
boost::intrusive_ptr<some_resource> r2(r);
std::cout << "Program exiting" << std::endl;
return EXIT_SUCCESS;
}
ここで結果が返されます。
Resource created
Resource referenced: 1
Resource referenced: 2
Program exiting
Resource unreferenced: 1
Resource unreferenced: 0
Resource destroyed
*** Program Exit ***
私は、あなたが「何のweak_ptr」と述べていない知っているが、なぜありませんか?頭部へのweak_ptrを尾へのweak_ptrで頭を持つ、と尾はサイクルを防ぐことができます。