Protobuf, understand the hood

proto文件定义

package lm;

message Foo{
    required int32 id = 1;
}

message Bar{
    required int32  id = 1 [default = 12];
    required string str= 2 [default = "bar::str"];
    required Foo    foo= 3;
}

下面分析protoc编译生成的:ph.b和pb.cc文件。

初始化

protoc会定义一个全局对象:

struct StaticDescriptorInitializer_lm_2ehelloworld_2eproto {
  StaticDescriptorInitializer_lm_2ehelloworld_2eproto() {
    protobuf_AddDesc_lm_2ehelloworld_2eproto();
  };
} static_descriptor_initializer_lm_2ehelloworld_2eproto_;

其中protobuf_AddDesc_lm_2ehelloworld_2eproto()函数完成了默认值的初始化:


void protobuf_AddDesc_lm_2ehelloworld_2eproto() {
  static bool already_here = false;
  ...
  Foo::default_instance_ = new Foo();
  Bar::_default_str_ =
      new ::std::string("bar::str", 8); // string默认值存在这里
  Bar::default_instance_ = new Bar();
  Foo::default_instance_->InitAsDefaultInstance();
  Bar::default_instance_->InitAsDefaultInstance();
  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_lm_2ehelloworld_2eproto);
}

同时注册了清理函数protobuf_ShutdownFile_lm_2ehelloworld_2eproto

void protobuf_ShutdownFile_lm_2ehelloworld_2eproto() {
  delete Foo::default_instance_;
  delete Foo_reflection_;
  delete Bar::default_instance_;
  delete Bar_reflection_;
  delete Bar::_default_str_;
}

构造

默认值的赋值在构造函数里:

Bar::Bar()
  : ::google::protobuf::Message() {
  SharedCtor();
  // @@protoc_insertion_point(constructor:lm.Bar)
}

void Bar::SharedCtor() {
  ::google::protobuf::internal::GetEmptyString();
  _cached_size_ = 0;
  id_ = 12; // id默认值
  str_ = const_cast< ::std::string*>(_default_str_); // str默认值
  foo_ = NULL;
  ::memset(_has_bits_, 0, sizeof(_has_bits_));
}

整数标示符的名称为kXxxFieldNumber

class Bar : public ::google::protobuf::Message {
    public:
        static const int kIdFieldNumber  = 1;
        static const int kStrFieldNumber = 2;
        static const int kFooFieldNumber = 3;
};

析构

新建的对象在析构函数里删除:

Bar::~Bar() {
  // @@protoc_insertion_point(destructor:lm.Bar)
  SharedDtor();
}

void Bar::SharedDtor() {
  if (str_ != _default_str_) {
    delete str_;
  }
  if (this != default_instance_) {
    delete foo_;
  }
};

Mutable Pointer

使用mutable_xxx()时,如果没有set过,则new一个新对象出来返回:

inline ::std::string* Bar::mutable_str() {
  set_has_str();
  if (str_ == _default_str_) {
    str_ = new ::std::string(*_default_str_);
  }
  return str_;
}

inline ::lm::Foo* Bar::mutable_foo() {
  set_has_foo();
  if (foo_ == NULL) foo_ = new ::lm::Foo;
  return foo_;
}

Allocate Value

使用set_allocated_xxx()时,清理掉原来的对象,用新对象赋值:

inline void Bar::set_allocated_str(::std::string* str) {
  if (str_ != _default_str_) {
    delete str_;
  }
  if (str) {
    set_has_str();
    str_ = str;
  } else {
    clear_has_str();
    str_ = const_cast< ::std::string*>(_default_str_);
  }
}

inline void Bar::set_allocated_foo(::lm::Foo* foo) {
  delete foo_;
  foo_ = foo;
  if (foo) {
    set_has_foo();
  } else {
    clear_has_foo();
  }
}

Clear

Clear()时重设为默认值:


void Bar::Clear() {
  if (_has_bits_[0 / 32] & 7) {
    id_ = 12;
    if (has_str()) {
      if (str_ != _default_str_) {
        str_->assign(*_default_str_);
      }
    }
    if (has_foo()) {
      if (foo_ != NULL) foo_->::lm::Foo::Clear();
    }
  }
  ::memset(_has_bits_, 0, sizeof(_has_bits_));
  mutable_unknown_fields()->Clear();
}

从这里面看出,只是重新赋值,如果是allocated的值,不会清理,所以需要allocate的人自己管理内存。

posted @ 2014-12-16 17:23  n0p  阅读(884)  评论(0编辑  收藏  举报