私はGotWのような主要なC++フォーラム/ブログで説明されている循環参照を壊す次の方法をまだ見つけられていないので、その技術が知られているかどうか、その賛否両論は何か?外部からstd :: weak_ptrとエイリアスコンストラクタを使用して循環参照を破る:健全か問題ありますか?
class Node : public std::enable_shared_from_this<Node> {
public:
std::shared_ptr<Node> getParent() {
return parent.lock();
}
// the getter functions ensure that "parent" always stays alive!
std::shared_ptr<Node> getLeft() {
return std::shared_ptr<Node>(shared_from_this(), left.get());
}
std::shared_ptr<Node> getRight() {
return std::shared_ptr<Node>(shared_from_this(), right.get());
}
// add children.. never let them out except by the getter functions!
public:
std::shared_ptr<Node> getOrCreateLeft() {
if(auto p = getLeft())
return p;
left = std::make_shared<Node>();
left->parent = shared_from_this();
return getLeft();
}
std::shared_ptr<Node> getOrCreateRight() {
if(auto p = getRight())
return p;
right = std::make_shared<Node>();
right->parent = shared_from_this();
return getRight();
}
private:
std::weak_ptr<Node> parent;
std::shared_ptr<Node> left;
std::shared_ptr<Node> right;
};
すべてので、Node
のユーザーがgetLeft
とgetRight
にエイリアシングコンストラクタを使用してトリックを気付くことはありませんが、それでもユーザーはgetParent
は常に非空の共有のポインタを返すことを確認することができますp->get{Left,Right}
によって返されたポインタは、返された子ポインタの存続期間中オブジェクト*p
を生きたままにします。
私はここで何かを見落としているのですか?これは既に文書化されている循環参照を壊す明白な方法ですか?あなたのgetParent
によって返さ
int main() {
auto n = std::make_shared<Node>();
auto c = n->getOrCreateLeft();
// c->getParent will always return non-null even if n is reset()!
}
これは、最終的にすべての子*がルートと同じ参照カウントを共有することを意味しますか?つまり、エイリアシングコンストラクタで 'left_A'を作成すると、参照カウントは' parent'と同じになります。次に、私が新しい 'left_B 'を作成し、' left_A-> shared_from_this'を使用すると、間接参照がツリーの上に続き、参照カウントがまだ 'parent'ですか?その場合、すべてのノードが同じ参照カウントを共有するため、ツリー全体が削除されるまで、ノードを削除してリソースをリサイクルすることはできません。 –
@SteveLorimer彼らは、ノードの 'get'関数の1つによって外界に与えられていない限り、ルートの参照カウントを共有しません(別のノードによって与えられたものです。その根)。誰かが子ノードへの参照を持っていない限り(おそらく、非同期操作中にツリーを歩いているときに一時的にしか起こらない)、参照カウントは共有されず、リソースを解放することができます。 –