递归创建boost属性树

时间:2015-04-08 17:35:17

标签: c++ boost boost-propertytree

我正在尝试从已有的树结构创建一个boost属性树。我在ptree node = *p行上收到了memeroy访问冲突错误。

我应该如何更改此代码才能使其正常工作?

ptree* WebTreeView::insertProjectNode(std::shared_ptr<ITreeNode> projectNode)
{

if (projectNode->Children().size() == 0)
{
    return nullptr;
}

ptree children;

for (auto child : projectNode->Children())
{
    std::shared_ptr<ITreeNode> c(child); // cast raw pointer to shared pointer
    std::string nodetext = c->Name().c_str();

    ptree *p = insertProjectNode(c);

    if (p)
    {
        ptree node = *p; 
        children.put_child(nodetext, node);
    }
    else
    {
        children.put(nodetext, " ");
    }
}

return &children;
}

2 个答案:

答案 0 :(得分:2)

最严重的罪犯

  1. 将悬空指针返回到本地ptree
  2. 这一行:

    std::shared_ptr<ITreeNode> c(child); // cast raw pointer to shared pointer
    

    那不是演员。它是一个转换构造函数。通过调用它转让所有权。这直接意味着您的循环删除原始ITreeNode树中的所有子项(因为当c被破坏时,它会隐式执行delete child,因为没有人else保存共享指针。

  3. 我正在简化代码。会稍微发帖。

    void WebTreeView::insertProjectNode(ITreeNode const& node, ptree& into) {
        ptree current;
    
        for (auto const* child : node.Children())
            if (child) insertProjectNode(*child, current);
    
        into.add_child(node.Name(), current);
    }
    

    或者,更接近您的界面(但缺少命名根的步骤:)

    ptree WebTreeView::insertProjectNode(ITreeNode const& node) {
        ptree current;
    
        for (auto const* child : node.Children())
            if (child) 
                current.add_child(child->Name(), insertProjectNode(*child));
    
        return current;
    }
    

    完整演示

    <强> Live On Coliru

    #include <boost/property_tree/ptree.hpp>
    #include <memory>
    #include <iostream>
    #include <list>
    
    struct ITreeNode {
        std::string Name() const { return _name; }
        std::list<ITreeNode *> const &Children() const { return _children; }
    
        ITreeNode(ITreeNode const&)            = delete;
        ITreeNode& operator=(ITreeNode const&) = delete;
    
        ITreeNode(std::string name = "", std::list<ITreeNode*> const& children = {})
            : _name(std::move(name)),
              _children(children)
        {
        }
    
        ~ITreeNode() {
            for (auto* c : _children)
                delete c; // TODO make depthfirst deletion using iteration instead
                          // of breadth-first using recursion to avoid
                          // stack-overflow on large trees
        }
      private:
        std::string _name;
        std::list<ITreeNode *> _children;
    };
    
    using boost::property_tree::ptree;
    
    namespace demo {
        ptree insertProjectNode(ITreeNode const& node);
    
        ptree insertProjectNode(ITreeNode const& node) {
            ptree current;
    
            for (auto const* child : node.Children())
                if (child) 
                    current.add_child(child->Name(), insertProjectNode(*child));
    
            return current;
        }
    }
    
    #include <boost/property_tree/xml_parser.hpp>
    
    int main() {
    
        ITreeNode const source = { "a", {
            new ITreeNode { "ab", {
                new ITreeNode { "ab0" },
                new ITreeNode { "ab1" },
                new ITreeNode { "ab2" },
            } },
            new ITreeNode { "ac", {
                new ITreeNode { "ac0" },
            } },
            new ITreeNode { "ad", {
                new ITreeNode { "ad0" },
                new ITreeNode { "ad1" },
                new ITreeNode { "ad2" },
                new ITreeNode { "ad3" },
            } },
        } };
    
        ptree root;
        root.add_child(source.Name(), demo::insertProjectNode(source));
    
        boost::property_tree::write_xml(std::cout, root,
                boost::property_tree::xml_writer_make_settings<std::string>(' ', 2));
    }
    

    打印

    <?xml version="1.0" encoding="utf-8"?>
    <a>
      <ab>
        <ab0/>
        <ab1/>
        <ab2/>
      </ab>
      <ac>
        <ac0/>
      </ac>
      <ad>
        <ad0/>
        <ad1/>
        <ad2/>
        <ad3/>
      </ad>
    </a>
    

答案 1 :(得分:1)

ptree children;是一个局部变量,当方法返回时,内存将不再有效。将其更改为ptree &children = *(new ptree());。但是在使用后你需要小心删除它。如果您的方法返回正常ptree而非指向ptree&#39;的指针,则会更安全。在这种情况下,您无需担心newdelete