5

子ノードのツリーを表す次のデータ構造 (ノード) の例を見てみましょう。各オブジェクトの子ノードのセットはマップに保存されます>

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

考え?

4

2 に答える 2