静态对象析构时yaml-cpp输出带双引号的YAML字符串异常
静态对象析构时yaml-cpp序列化字符串被强制加引号的问题
问题重现
当在静态对象的析构函数中使用yaml-cpp执行序列化时,会出现所有字符串(包括映射键)被双引号包裹的异常。普通对象场景下运行正常,且该异常仅在析构前调用过Serialize()函数时出现。
示例代码:
struct EmitterTest { ~EmitterTest() { Serialize(); } void Serialize() { YAML::Emitter out; out << YAML::BeginMap << YAML::Key << "Test"; out << YAML::BeginMap; out << YAML::Key << "String1" << YAML::Value << "String1"; out << YAML::Key << "String2" << YAML::Value << "String2"; out << YAML::Key << "String3" << YAML::Value << "Foo"; out << YAML::EndMap; out << YAML::EndMap; std::cout << out.c_str() << std::endl; } }; static EmitterTest s_Test; int main() { s_Test.Serialize(); }
预期输出
Test: String1: String1 String2: String2 String3: Foo Test: String1: String1 String2: String2 String3: Foo
实际输出
Test: String1: String1 String2: String2 String3: Foo "Test": "String1": "String1" "String2": "String2" "String3": "Foo"
原因分析
静态对象的析构时机处于程序退出阶段的全局对象销毁流程中,此时yaml-cpp内部的全局配置对象(负责判断字符串是否需要加引号的规则、格式选项等)可能已经被提前销毁。
- 第一次在
main()中调用Serialize()时,yaml-cpp的全局状态尚未被破坏,Emitter可以正常使用默认的字符串格式规则(符合YAML规范的纯文本字符串不加引号)。 - 当静态对象
s_Test析构时,yaml-cpp的全局配置已经失效,Emitter会 fallback 到最保守的序列化策略——给所有字符串添加双引号,以避免格式错误。
解决方案
方案1:避免在静态对象析构中执行序列化
将序列化逻辑从析构函数中移除,改为在程序退出前主动调用:
struct EmitterTest { // 移除析构函数中的Serialize调用 ~EmitterTest() = default; void Serialize() { YAML::Emitter out; out << YAML::BeginMap << YAML::Key << "Test"; out << YAML::BeginMap; out << YAML::Key << "String1" << YAML::Value << "String1"; out << YAML::Key << "String2" << YAML::Value << "String2"; out << YAML::Key << "String3" << YAML::Value << "Foo"; out << YAML::EndMap; out << YAML::EndMap; std::cout << out.c_str() << std::endl; } }; static EmitterTest s_Test; int main() { s_Test.Serialize(); // 程序退出前主动调用第二次序列化 s_Test.Serialize(); }
方案2:手动强制Emitter使用纯文本字符串格式
如果必须在析构函数中执行序列化,可以手动设置Emitter的字符串格式为Plain,强制所有符合YAML规范的字符串以无引号形式输出:
void Serialize() { YAML::Emitter out; // 强制使用纯文本格式输出字符串 out.SetStringFormat(YAML::StringFormat::Plain); out << YAML::BeginMap << YAML::Key << "Test"; out << YAML::BeginMap; out << YAML::Key << "String1" << YAML::Value << "String1"; out << YAML::Key << "String2" << YAML::Value << "String2"; out << YAML::Key << "String3" << YAML::Value << "Foo"; out << YAML::EndMap; out << YAML::EndMap; std::cout << out.c_str() << std::endl; }
该设置会绕过yaml-cpp的全局配置判断,直接使用指定的字符串格式,即使全局状态失效也能保证输出符合预期。
内容的提问来源于stack exchange,提问作者Krausler
相关产品推荐
相关产品推荐

