我一直在尝试为我自己的数据类型实现一些 yaml-cpp 的转换结构。其中有一个类,而不仅仅是一个结构。编码函数工作正常。但解码功能没有。我尝试从yaml文件中获取一个字符串并在类中设置正确的变量。
template<>
struct convert<EngineNode*> {
static Node encode(EngineNode *rhs) {
Node node;
std::string type;
if(rhs->type == 0) {
type = "node";
} else if(rhs->type == 1) {
type = "scene";
} else if(rhs->type == 3) {
type = "particle";
}
node[type]["name"] = rhs->name;
node[type]["type"] = rhs->type;
node[type]["velocity"] = rhs->getVelocity();
node[type]["position"] = rhs->getPosition();
node[type]["rotation"] = rhs->getRotation();
for(unsigned i = 0; i < rhs->children.size(); i++) {
if(rhs->children[i]->type == SPRITE) {
node[type]["children"].push_back((SpriteNode*)rhs->children[i]);
} else {
node[type]["children"].push_back(rhs->children[i]);
}
}
return node;
}
static bool decode(const Node& node, EngineNode *rhs) {
if((!node["root"]["node"].IsDefined()) && (!node["root"]["scene"].IsDefined()) && (!node["particle"].IsDefined())) {
return false;
}
std::string type;
if(node["root"]["node"].IsDefined()) {
type = "node";
} else if(node["root"]["scene"].IsDefined()) {
type = "scene";
}
const Node n = node["root"][type];
rhs->name = n["name"].as<std::string>();
rhs->type = n["type"].as<int>();
rhs->setVelocity(n["velocity"].as<Velocity>());
rhs->setPosition(n["position"].as<Point>());
rhs->setRotation(n["rotation"].as<float>());
for(unsigned i = 0; i < n["children"].size(); i++) {
if(n["children"]["type"].as<int>() == SPRITE) {
rhs->addChild(n["children"].as<SpriteNode*>());
} else {
rhs->addChild(n["children"].as<EngineNode*>());
}
}
return true;
}
};
如果你想看看完整的源代码,它在github。
问题是它出现以下错误:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff73e3b5c in std::string::assign(std::string const&) () from /usr/lib/libstdc++.so.6
(gdb) bt
#0 0x00007ffff73e3b5c in std::string::assign(std::string const&) () from /usr/lib/libstdc++.so.6
#1 0x000000000040f590 in YAML::convert<EngineNode*>::decode (node=..., rhs=0x8) at src/yaml_config.cpp:90
#2 0x000000000040ef9f in YAML::as_if<EngineNode*, void>::operator() (this=0x7fffffffe4c0) at /usr/include/yaml-cpp/node/impl.h:119
#3 0x0000000000407a7d in YAML::Node::as<EngineNode*> (this=0x7fffffffe5c8) at /usr/include/yaml-cpp/node/impl.h:143
#4 0x00000000004074f9 in YamlConfig::readNode (this=0x8cf810, yaml_node=...) at src/yaml_config.cpp:172
#5 0x000000000040739a in YamlConfig::read (this=0x8cf810, path=...) at src/yaml_config.cpp:161
#6 0x0000000000404fa5 in GameScene::GameScene (this=0x8d62d0) at game/gamescene.cpp:16
#7 0x0000000000404205 in Main::initGameScene (this=0x61d2b0) at src/main.cpp:75
#8 0x0000000000404480 in main () at src/main.cpp:145
我不知道为什么会发生这种情况,这可能与 yaml-cpp 完全无关,而只是我对模板和这里使用的其他东西的理解非常有限。(我只知道非常基本的c ++)
任何帮助将不胜感激,
彼得
问题是 Node::as<T>
函数在堆栈上分配一个 T
类型的变量,然后使用复制语义返回转换后的值。在上面的例子中,T
是EngineNode *
,它是一个指向EngineNode
的指针。as
函数不会为实际的EngineNode
分配额外的内存,所以取消引用(使用*
或->
)会导致分割错误。
解决方法是重新设计转换函数以使用引用而不是指针:
template<>
struct convert<EngineNode> {
static Node encode(const EngineNode &rhs) {
Node node;
std::string type;
if(rhs.type == 0) {
type = "node";
} else if(rhs.type == 1) {
type = "scene";
} else if(rhs.type == 3) {
type = "particle";
}
// ...
}
static bool decode(const Node& node, EngineNode &rhs) {
if((!node["root"]["node"].IsDefined()) && (!node["root"]["scene"].IsDefined()) && (!node["particle"].IsDefined())) {
return false;
}
std::string type;
if(node["root"]["node"].IsDefined()) {
type = "node";
} else if(node["root"]["scene"].IsDefined()) {
type = "scene";
}
const Node n = node["root"][type];
rhs.name = n["name"].as<std::string>();
// ...
}
};
确保已为 EngineNode
类定义了适当的复制构造函数:
class EngineNode {
public:
EngineNode();
EngineNode(const EngineNode &rhs); // Copy-constructor
~EngineNode();
// ...
};
这样,当您的EngineNode
在 YamlConfig::read
中分配时,如果像这样重写,它将创建一个有效的副本:
EngineNode *YamlConfig::read(std::string path) {
YAML::Node doc = YAML::LoadFile(path);
EngineNode *node = new EngineNode(doc.as<EngineNode>());
// ...
return node;
}
任何调用此函数的人都应该知道,这会在堆上分配一个新的EngineNode
对象。此对象可能需要在某个时候通过调用delete
来释放。或者,您可以重新设计 API 以使用智能指针:
std::shared_ptr<EngineNode> YamlConfig::read(std::string path) {
YAML::Node doc = YAML::LoadFile(path);
auto node = std::make_shared(doc.as<EngineNode>());
// ...
return node;
}