You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

静态对象析构时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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:02:21