递归添加子树以提升属性树
Posted
技术标签:
【中文标题】递归添加子树以提升属性树【英文标题】:Recursively adding subtrees to boost property tree 【发布时间】:2018-06-13 12:08:32 【问题描述】:我想用 C++ 编写一个参数服务器,我可以在其中递归地将参数树转储到属性树中,然后将其写入 JSON 文件。 转储函数如下所示:
void Params::dump(string filename)
// Create a root
pt::ptree root;
// Fill the root with parameters
mapToPt(curParams, root);
// Write to cout
pt::write_json(cout, root);
mapToPt 应该递归地遍历我的参数服务器的层次结构并在这样做时填充属性树:
void Params::mapToPt(boost::shared_ptr<Params> curParams, pt::ptree &root)
// Fill current root with parameters from curParams ParameterMap
map<string, boost::shared_ptr<Param> >::iterator it;
for ( it = curParams->getParamMap().begin(); it != curParams-getParamMap().end(); it++ )
root.put(it->first, it->second->getValue());
cout << "Add Parameter: \n";
cout << "Parameter name: " << it->first << "\n";
cout << "Parameter value: " << it->second->getValue() << "\n";
// Recursively go through all children to do the same to them
if(curParams->hasChildren()) //ERROR LINE
map<string, boost::shared_ptr<Params> >::iterator it;
for ( it = curParams->getChildren().begin(); it != curParams-getChildren().end(); it++ )
pt::ptree new_tree;
root.add_child(it->second->getName(), new_tree);
cout << "Add Child: \n";
cout << "Child name: " << it->second->getName() << "\n";
mapToPt(it->second, new_tree);
我的问题是,一旦我进入递归,错误就会发生在随机行,这不是错误的原因。 “basic_string::_M_construct null not valid”是错误消息。我相信我可能会访问已删除的内容,这可能是由于我遍历属性树子项的方式。 是我做错了还是有其他方法?
谢谢。
【问题讨论】:
如果hasChildren()
是错误行,那是如何实现的?
【参考方案1】:
当mapToPt
还需要一个指向Params
实例的指针时,为什么它是一个成员?
Anyhoops,有相当多的混乱。
在设计级别,您的 Params
类型看起来无法确定它是否是叶节点。此外,它受到“准类”设计的影响,其中 getter 基本上保证没有类不变量是可能的。在这种情况下,最好只使用一个带有成员字段的结构。
注意,如果您未能从
getParamMap()
和getChildren()
返回引用,那么您已经在两个循环中拥有Undefined Behaviour,因为迭代器会指向不存在的容器副本.你应该检查一下。另外,请参阅下面的工作演示
在实施层面,这会给您带来问题:
pt::ptree new_tree;
root.add_child(it->second->getName(), new_tree);
add_child
插入new_tree
的副本。以后对new_tree
的任何修改都无效。相反,写:
pt::ptree& new_tree = root.add_child(it->second->getName(), );
这里,new_tree
成为实际添加的树的引用。
尝试修复
风格仍然低于我的预期。我个人会仔细审查这段代码中shared_ptr
的使用。
但这可能会帮助你:
Live On Coliru
#include <boost/make_shared.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include <map>
namespace pt = boost::property_tree;
struct Param
std::string getValue() const return "42";
;
struct Params
using ParamMap = std::map<std::string, boost::shared_ptr<Param> >;
using Children = std::map<std::string, boost::shared_ptr<Params> >;
Params(std::string name = "") : _name(name)
std::string getName() const return _name;
ParamMap& getParamMap() return _map;
ParamMap const& getParamMap() const return _map;
bool hasChildren() const return !_children.empty();
Children& getChildren() return _children;
Children const& getChildren() const return _children;
static void mapToPt(boost::shared_ptr<Params> curParams, pt::ptree &root);
private:
std::string _name;
ParamMap _map;
Children _children;
;
void Params::mapToPt(boost::shared_ptr<Params> curParams, pt::ptree &root)
// Fill current root with parameters from curParams ParameterMap
std::map<std::string, boost::shared_ptr<Param> >::iterator it;
for (it = curParams->getParamMap().begin(); it != curParams->getParamMap().end(); it++)
root.put(it->first, it->second->getValue());
//std::cout << "Add Parameter: \n";
//std::cout << "Parameter name: " << it->first << "\n";
//std::cout << "Parameter value: " << it->second->getValue() << "\n";
// Recursively go through all children to do the same to them
if (curParams->hasChildren())
for (auto it = curParams->getChildren().begin(); it != curParams->getChildren().end(); it++)
pt::ptree& new_tree = root.add_child(it->second->getName(), );
//std::cout << "Add Child: \n";
//std::cout << "Child name: " << it->second->getName() << "\n";
mapToPt(it->second, new_tree);
int main()
auto a = boost::make_shared<Params>("rootparams");
a->getParamMap().emplace("one", boost::make_shared<Param>());
a->getParamMap().emplace("two", boost::make_shared<Param>());
a->getParamMap().emplace("three", boost::make_shared<Param>());
a->getChildren().emplace("child1", boost::make_shared<Params>("child1-name"))
.first->second->getParamMap().emplace("four", boost::make_shared<Param>());
a->getChildren().emplace("child2", boost::make_shared<Params>("child2-name"))
.first->second->getParamMap().emplace("five", boost::make_shared<Param>());
pt::ptree root;
a->mapToPt(a, root);
write_json(std::cout, root);
打印
"one": "42",
"three": "42",
"two": "42",
"child1-name":
"four": "42"
,
"child2-name":
"five": "42"
【讨论】:
以上是关于递归添加子树以提升属性树的主要内容,如果未能解决你的问题,请参考以下文章