子ノードのツリーを表す次のデータ構造 (ノード) の例を見てみましょう。各オブジェクトの子ノードのセットはマップに保存されます>
class Node;
typedef std::shared_ptr<Node> NodePtr;
class Node
{
std::map<const std::string, NodePtr> _childNodes;
void SomeOtherMethod();
public:
bool GetChildByKeyName(/*In*/ const std::string& key, /*Out*/ NodePtr& spChild)
{
bool result = false;
auto itor = _childNodes.find(key);
if (itor != _childNodes.end())
{
spChild = itor->second;
result = true;
SomeOtherMethod();
}
return result;
}
};
次のコード サンプルは、ユーザーが通常呼び出すものです。
NodePtr spNode, spChildNode;
bool result;
...
result = spNode->GetChildByKeyName(strChildKeyName, spChildNode);
ここまでは順調ですね。
呼び出し元は、ツリーの深さごとに追加の変数を処理する必要なく、ツリーをトラバースする方法があるのではないかと思いました。
NodePtr spNode;
bool result;
result = spNode->GetChildItem(strChildKeyName, spNode);
if (result)
spNode->GetChildItem(strSubKeyName, spNode);
上記の場合、spNode がオブジェクトへの最後の残りの参照である場合、GetChildItem メソッドの次のコード ブロックが心配です。
spChild = itor->second;
result = true;
SomeOtherMethod();
spChild (実際には呼び出し元の spNode インスタンス) の割り当てによって、最後の参照がなくなったために「この」ノードが誤って破壊されていませんか? (したがって、spChild の代入後に他のメソッドを呼び出すのは危険です)。ここに潜在的なバグがありますか?
回避策は、メソッド呼び出しの先頭に次の行を追加することだと思います。
NodePtr spChildRef = spChild; // maintain a reference to the caller's original node during the scope of the method
考え?