动态生成protobuf消息并返回指向它的指针

时间:2017-02-28 14:35:22

标签: c++ protocol-buffers

首先,我对C ++不是很有经验,所以也许我在这里监督一些事情。 我尝试使用以下代码从.proto文件动态生成protobuf消息:

int init_msg(const std::string & filename, protobuf::Arena* arena, protobuf::Message** new_msg){
  using namespace google::protobuf;
  using namespace google::protobuf::compiler;

  DiskSourceTree source_tree;
  source_tree.MapPath("file", filename);

  MuFiErCo error_mist;
  Importer imp(&source_tree, &error_mist);

  printf("Lade Datei:%s \n", filename.c_str());

  const FileDescriptor* f_desc = imp.Import("file");

  const Descriptor* desc = f_desc->FindMessageTypeByName("TestNachricht");

  const Message* new_msg_proto = dmf.GetPrototype(desc);

  *new_msg = new_msg_proto->New(arena);

  //Debug
  cout << (*new_msg)->GetTypeName() << endl;

  return 0;
}

int main(int argc, char* argv[]){

  protobuf::Arena arena;

  protobuf::Message *adr2, *adr1;

  init_msg("schema-1.proto", &arena, &adr1);
  init_msg("schema-1.proto", &arena, &adr2);

  printf("MSG_Pointer: %p, %p\n", adr1, adr2);

  cout << adr1->GetTypeName() << endl;

  arena.Reset();

  return 0;
}    

我想如果我使用Arena,新的Message也可以在函数范围之外使用。 但是如果我尝试访问Message,总会出现段错误。 我想这是一个简单的错误,但我无法弄清楚,如何解决这个问题。

这是输出:

Lade Datei:schema-1.proto 
packet.TestNachricht
Lade Datei:schema-1.proto 
packet.TestNachricht
MSG_Pointer: 0x1b293b0, 0x1b287f0
Speicherzugriffsfehler (Speicherabzug geschrieben)

1 个答案:

答案 0 :(得分:1)

  

我认为,问题是FileDescriptor等在被破坏时被破坏了   init_msg返回,无法保留新创建的消息   询问其.proto定义。您需要移动Importer   实例主要并保持活着。这与此无关   竞技场。 - Igor Tandetnik

这就是解决方案。

这是一些工作示例代码

#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <memory>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/arena.h>


using namespace std;
using namespace google::protobuf;


class MuFiErCo : public compiler::MultiFileErrorCollector
{
public:
    void AddError(const string & filename, int line, int column, const string & message){
        printf("Err: %s\n", message.c_str());
    }
    void AddWarning(const string & filename, int line, int column, const string & message){
        printf("Warn: %s\n", message.c_str());
    }

};


compiler::Importer* init_proto_dir(Arena* arena, const std::string &root_dir){
    using namespace compiler;

    static DiskSourceTree source_tree;
    source_tree.MapPath("", root_dir);

    static MuFiErCo error_mist;
    static Importer* imp = Arena::Create<Importer>(arena, &source_tree, &error_mist);

    return imp;
}


void init_proto_def(compiler::Importer* imp, const std::string &proto_file){
    using namespace compiler;

    imp->Import(proto_file);

    return;
}


Message* init_msg(compiler::Importer* imp, Arena* arena, const std::string &msg_name){

    const DescriptorPool* pool = imp->pool();

    static DynamicMessageFactory dmf;

    const Descriptor* desc = pool->FindMessageTypeByName(msg_name);

    const Message* msg_proto = dmf.GetPrototype(desc);

    return msg_proto->New(arena);
}


int set_value(Message* msg, const char* value_name, unsigned long int value){
    const Message::Reflection* reflec = msg->GetReflection();
    const Descriptor* desc = msg->GetDescriptor();

    const FieldDescriptor* fdesc = desc->FindFieldByName(value_name);

    reflec->SetUInt64(msg, fdesc, value);

    return 0;

}


int main(int argc, char* argv[]){

    Arena arena;

    compiler::Importer* imp = init_proto_dir(&arena, "");
    init_proto_def(imp, "schema-1.proto");

    Message* msg = init_msg(imp, &arena, "packet.TestNachricht");

    set_value(msg, "zahl", 23434);

    cout << msg->DebugString() << endl;

    return 0;
}