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

使用Boost ASIO+RapidJSON传输对象时IsObject()断言失败求助

解决RapidJSON解析时Assertion `IsObject()' failed的问题

这个错误的核心原因很明确:当你尝试用document["key"]访问成员时,document并不是一个有效的JSON对象。结合你的代码和输出来看,问题出在UDP接收的字符串处理不当,导致RapidJSON解析失败。

问题根源

你用boost::array<char, 2048> recv_buf接收数据,然后直接通过std::string json(recv_buf.data())构造字符串。但UDP接收的实际数据长度远小于2048,这就导致构造出的字符串包含了recv_buf中从有效数据结束到数组末尾的所有垃圾字符(比如输出里开头的E�)。这些垃圾字符破坏了JSON的语法,让RapidJSON解析失败,最终document不是一个合法的Object,触发了断言。

解决方案

1. 正确截取实际接收的字节数

receive_from函数会返回实际接收的字节数,你需要用这个长度来构造字符串,只保留有效数据:

void BoostClient::receivePacket() {
    boost::array<char, 2048> recv_buf;
    udp::endpoint sender_endpoint;
    // 保存实际接收的字节数
    size_t bytes_received = static_cast<udp::socket *>(socket_)->receive_from(
        boost::asio::buffer(recv_buf), sender_endpoint);
    // 仅使用前bytes_received个字符构造JSON字符串
    std::string json(recv_buf.data(), bytes_received);
    std::cout << "received: " << json << std::endl;
    Data data(json);
    data.print();
};

2. 增加解析错误检查

即使字符串正确,也应该在解析时做合法性校验,避免崩溃:

Data(std::string data) {
    rapidjson::Document document;
    // 保存解析结果,检查是否成功
    rapidjson::ParseResult parse_result = document.Parse(data.c_str());
    
    if (!parse_result || !document.IsObject()) {
        std::cerr << "JSON解析失败或不是Object类型: " << data << std::endl;
        std::cerr << "错误码: " << parse_result.Code() << ", 错误位置: " << parse_result.Offset() << std::endl;
        return;
    }

    // 逐个检查成员是否存在且类型正确,避免访问非法成员
    if (document.HasMember("rotation") && document["rotation"].IsString()) {
        rotation_ = std::stof(document["rotation"].GetString());
    }
    if (document.HasMember("size") && document["size"].IsString()) {
        size_ = std::stof(document["size"].GetString());
    }
    if (document.HasMember("collide") && document["collide"].IsString()) {
        collide_ = std::stoi(document["collide"].GetString());
    }
    if (document.HasMember("lifePoint") && document["lifePoint"].IsString()) {
        lifePoint_ = std::stoi(document["lifePoint"].GetString());
    }
    if (document.HasMember("id") && document["id"].IsString()) {
        id_ = std::stoi(document["id"].GetString());
    }
    if (document.HasMember("type") && document["type"].IsString()) {
        type_ = std::stoi(document["type"].GetString());
    }
    if (document.HasMember("pos.x") && document["pos.x"].IsString()) {
        pos_.first = std::stof(document["pos.x"].GetString());
    }
    if (document.HasMember("pos.y") && document["pos.y"].IsString()) {
        pos_.second = std::stof(document["pos.y"].GetString());
    }
};

3. 优化JSON生成格式(可选但推荐)

你当前生成的JSON中,数值都是字符串类型(比如"1.000000"),这不符合JSON的最佳实践,也增加了解析复杂度。建议用RapidJSON的Writer直接生成数值类型的JSON:

std::string getJson() {
    rapidjson::StringBuffer buffer;
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
    
    writer.StartObject();
    writer.Key("rotation"); writer.Double(rotation_);
    writer.Key("size"); writer.Double(size_);
    writer.Key("collide"); writer.Int(collide_);
    writer.Key("lifePoint"); writer.Int(lifePoint_);
    writer.Key("id"); writer.Int(id_);
    writer.Key("type"); writer.Int(type_);
    writer.Key("pos.x"); writer.Double(pos_.first);
    writer.Key("pos.y"); writer.Double(pos_.second);
    writer.EndObject();
    
    return buffer.GetString();
};

这样生成的JSON中数值是原生Number类型,解析时可以直接用GetFloat()/GetInt(),不需要字符串转换,更高效也更安全。

总结

先修复UDP接收的字符串截取问题,这是导致断言失败的直接原因;再增加解析校验,让程序更健壮;最后优化JSON生成格式,遵循规范。按这个步骤修改后,你的程序应该就能正常运行了。

内容的提问来源于stack exchange,提问作者Gancar_d

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:15:39