递归添加子树以提升 属性 树
Recursively adding subtrees to boost property tree
我想用 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" 是错误信息。我相信我可能会访问已删除的内容,这可能是由于我遍历 属性 树子项的方式所致。
我的做法是错误的还是有其他方法?
谢谢。
为什么 mapToPt
也是一个成员,而它也需要一个指向 Params
实例的指针?
哎呀,有点混乱。
在设计层面,您的 Params
类型看起来无法决定它是否是叶节点。此外,它受到 "Quasi Classes" 设计的影响,其中 getters 基本上保证没有 class 不变性。在这种情况下,宁愿只拥有一个包含成员字段的结构。
Note, if you fail to return by reference from getParamMap()
and getChildren()
then you already have Undefined Behaviour in both loops, because the iterators then point into non-existent copies of containers.
You should check this. Also, see my working demo below
在实施层面,这给您带来了问题:
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
的使用。
但这可能会对您有所帮助:
#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"
}
}
我想用 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" 是错误信息。我相信我可能会访问已删除的内容,这可能是由于我遍历 属性 树子项的方式所致。 我的做法是错误的还是有其他方法?
谢谢。
为什么 mapToPt
也是一个成员,而它也需要一个指向 Params
实例的指针?
哎呀,有点混乱。
在设计层面,您的 Params
类型看起来无法决定它是否是叶节点。此外,它受到 "Quasi Classes" 设计的影响,其中 getters 基本上保证没有 class 不变性。在这种情况下,宁愿只拥有一个包含成员字段的结构。
Note, if you fail to return by reference from
getParamMap()
andgetChildren()
then you already have Undefined Behaviour in both loops, because the iterators then point into non-existent copies of containers.You should check this. Also, see my working demo below
在实施层面,这给您带来了问题:
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
的使用。
但这可能会对您有所帮助:
#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"
}
}