【问题标题】:Parse json file from AWS S3 with C++ and Jsoncpp使用 C++ 和 Jsoncpp 从 AWS S3 解析 json 文件
【发布时间】:2019-02-06 11:23:59
【问题描述】:

我有这个 C++ 函数,它使用 AWS SDK C++ 将 S3 文件下载为 istreams

std::istream& s3read(std::string bucket, std::string key) {
    Aws::Client::ClientConfiguration aws_conf;
    aws_conf.region = Aws::Environment::GetEnv("AWS_REGION");
    aws_conf.caFile = "/etc/pki/tls/certs/ca-bundle.crt";
    Aws::S3::S3Client s3_client(aws_conf);
    Aws::S3::Model::GetObjectRequest object_request;
    object_request.WithBucket(bucket.c_str()).WithKey(key.c_str());
    auto get_object_outcome = s3_client.GetObject(object_request);

    if (get_object_outcome.IsSuccess()) {
        std::istream& res = get_object_outcome.GetResult().GetBody();
        return res;
    } else {
        ...
    };
};

我从 main.cpp 调用它并尝试用 Jsoncpp 解析它:

std::istream& stream = s3read(bucket, key);
Json::Value json;
Json::Reader reader;
reader.parse(stream, json);

但是,我不断收到分段错误。为什么?

我认为问题在于 reader.parse 需要二进制数据,而 istream 不需要。但是,如果我是对的,如何将流解析为二进制?

【问题讨论】:

  • 函数get_object_outcome内部是一个local变量。因此,它的生命将在函数结束时结束,这意味着对它或对象内部成员的所有引用都将变得无效。使用此类引用将导致undefined behavior 并可能导致崩溃。
  • 您的问题是std::istream& res = get_object_outcome.GetResult().GetBody(); return res; 检查编译器警告(全部启用)。您正在返回对本地对象的引用(地址),就在 s3read 调用 get_object_outcome 已经被销毁之后,因此流对象的地址不再显示在打开的输入流中。
  • 你能做什么 - 从 s3read 返回解析的 json 对象

标签: c++ amazon-web-services aws-lambda jsoncpp aws-sdk-cpp


【解决方案1】:

你遇到的问题很经典returning reference to temporary

您可以稍微重新设计您的代码,以避免这种情况。例如:

static Json::Value parse_json(std::istream& src) {
     Json::Value ret;
     Json::Reader reader;
     reader.parse(src, ret);
     return ret;  
}
// Aws::String is actually same thing to std::string except the allocator
// in case of Android, otherwise this is std::string as it is. 
// You can use function like s3read("foo","bar");  
Json::Value s3read_json(const Aws::String& bucket,const Aws::String& key) {
    static constexpr const char *FILE_NAME = "/etc/pki/tls/certs/ca-bundle.crt";

    Aws::Client::ClientConfiguration aws_conf;
    aws_conf.region = Aws::Environment::GetEnv("AWS_REGION");
    aws_conf.caFile = FILE_NAME;

    Aws::S3::S3Client s3_client(aws_conf);
    Aws::S3::Model::GetObjectRequest object_request;
    object_request.WithBucket( bucket ).WithKey( key );

    auto object_outcome = s3_client.GetObject(object_request);

    if (object_outcome.IsSuccess()) {
        auto result = object_outcome.GetResult();
        // destructor of object_outcome is not yet called
        return parse_json( result.GetBody() );
    } else {
        ...
        // throw std::runtime_error("S3 connection failed");
    };
};

【讨论】:

    猜你喜欢
    • 2012-03-21
    • 2018-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多