protobuf 中的嵌套消息的使用 主要对set_allocated_和mutable_的使用

protobuf的简单的使用,不过还留下了一个问题,那就是之前主要介绍的都是对简单数据的赋值,简单数据直接采用set_xx()即可,但是如果不是简单变量而是自定义的复合类型变量,就没有简单的set函数调用了,下面看一个简单的例子。

在网络游戏中,游戏玩家之间的同步是一个最基本的功能,而同步是通过对坐标的广播进行的,因此我们假设一个简单的模型,当一个玩家的位置发生变化时,将玩家的新位置发给地图内所有玩家,根据这个情况写出以下proto文件。

[cpp] view plain copy

  1. message PlayerPos
  2. {
  3. required  uint32  playerID = 1;
  4. required  float   posX = 2 ;
  5. required  float   posY = 3 ;
  6. };
  7. file  vector.protomessage  vector3D
  8. {
  9. required float x = 1;
  10. required float y = 2;
  11. required float z = 3;
  12. };

这样就有一个问题,现在的游戏都是3D游戏,因此需要xyz来表示位置,还需要另一组xyz来表示朝向,如果用简单变量的话就会显的很乱,而且无论是位置还是朝向其实都是一组xyz,因此可以将xyz抽出来成为一个复合数据类型,单独放在一个文件中。这样就构成以下文件。

[cpp] view plain copy

  1. file  Player.protoimport "vector.proto";
  2. message PlayerPos
  3. {
  4. required uint32 playerID = 1;
  5. required vector3D  pos = 2;
  6. };

编译的时候先编译vector文件,采用import时需要注意路径,本例中两文件在同一目录下。

[cpp] view plain copy

  1. protoc --cpp_out=.  vector.proto  Player.proto

proto对应的文件已经生成了,但是该怎么赋值呢,查API查了半天有点不知所以,干脆来看生成的类文件的源代码吧

[cpp] view plain copy

  1. // required uint32 playerID = 1;
  2. inline bool has_playerid() const;
  3. inline void clear_playerid();
  4. static const int kPlayerIDFieldNumber = 1;
  5. inline ::google::protobuf::uint32 playerid() const;
  6. inline void set_playerid(::google::protobuf::uint32 value);
  7. // required .vector3D pos = 2;
  8. inline bool has_pos() const;
  9. inline void clear_pos();
  10. static const int kPosFieldNumber = 2;
  11. inline const ::vector3D& pos() const;
  12. inline ::vector3D* mutable_pos();
  13. inline ::vector3D* release_pos();
  14. inline void set_allocated_pos(::vector3D* pos);

上面列出了生成的部分源代码,主要是PlayerPos的操作变量的函数,第一个playID很简单,可以看到直接使用set_playerid ( ) 即可,但是对于嵌套的pos 发现没有对应的set_pos方法,不过发现了一个set_allocated_pos() 函数,这个函数也是set开头的,看看这个函数是干嘛的。

[cpp] view plain copy

  1. inline void PlayerPos::set_allocated_pos(::vector3D* pos)
  2. {
  3. delete pos_;
  4. pos_ = pos;
  5. if (pos)
  6. {
  7. set_has_pos();
  8. }
  9. else {
  10. clear_has_pos();
  11. }
  12. }

看上去可以赋值,直接调用set_allocated_pos() 进行赋值看一看

[cpp] view plain copy

  1. PlayerPos player;
  2. vector3D  tmp;
  3. tmp.x = 1;
  4. tmp.y = 2;
  5. tmp.z = 3;
  6. player.set_allocated_pos(&tmp)

编译没问题,但是运行时出现错误,而且是很奇怪的错误,仔细了查看一下PlayerPos的源码,发现一个问题

[cpp] view plain copy

  1. ::vector3D* pos_;  ::google::protobuf::uint32 playerid_;

上面是PlayerPos中变量的保存形式,发现pos是作为一个指针存储的,如果按照之前的赋值 tmp 是一个局部变量,函数返回时局部变量自动销毁,而pos_保存的仍然是已被销毁的tmp的位置,因此会出错,如果采用new的话就可以解决这个问题,即赋值方法如下:

[cpp] view plain copy

  1. PlayerPos player;vector3D  *tmp = new Vector3D;
  2. tmp->x = 1;
  3. tmp->y = 2;
  4. tmp->z = 3;
  5. player.set_allocated_pos(tmp)

这样即可,编译运行都没有问题。 
如此之外,还有一种赋值方法,就是调用mutable_pos()

[cpp] view plain copy

  1. inline ::vector3D* PlayerPos::mutable_pos()
  2. {
  3. set_has_pos();
  4. if (pos_ == NULL)
  5. pos_ = new ::vector3D;
  6. return pos_;
  7. }

mutable_pos () 中自己new出了一个vector3D 对象,而vector3D中又实现了赋值的重载,因此可以这样解决:

[cpp] view plain copy

    1. PlayerPos player;
    2. vector3D  *tmp = player.mutable_pos();
    3. tmp->x = 1;
    4. tmp->y = 2;
    5. tmp->z = 3;
时间: 2024-10-14 10:33:23

protobuf 中的嵌套消息的使用 主要对set_allocated_和mutable_的使用的相关文章

protobuf 中的嵌套消息的使用

protobuf的简单的使用,不过还留下了一个问题,那就是之前主要介绍的都是对简单数据的赋值,简单数据直接采用set_xx()即可,但是如果不是简单变量而是自定义的复合类型变量,就没有简单的set函数调用了,下面看一个简单的例子. 在网络游戏中,游戏玩家之间的同步是一个最基本的功能,而同步是通过对坐标的广播进行的,因此我们假设一个简单的模型,当一个玩家的位置发生变化时,将玩家的新位置发给地图内所有玩家,根据这个情况写出以下proto文件.   message PlayerPos{ require

protobuf extensions(extend)的消息定义及Java使用方法

在定义protobuf消息时,有时候需要用到extensions来对原有的消息类型进行扩展,有利于消息定义的重复使用. 1.下面写一个最简单的例子,定义一个message BaseData,并对其进行扩展: Example.proto: // 定义一个message BaseData,100~199之间的tag可供扩展 message BaseData { required int32 code = 1; extensions 100 to 199; } // 扩展BaseData,加上一个ex

Win32编程中如何处理控制台消息

这篇文章讨论如何处理所有的控制台消息. 第一步,首先要安装一个事件钩子,也就是说要建立一个回调函数.调用Win32 API,原型如下: BOOL SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, // 回调函数BOOL Add // 表示添加还是删除): 参数HandlerRoutine是一个指向函数的指针,原型如下: BOOL WINAPI HandlerRoutine(DWORD dwCtrlType // 控制事件类型): 所有的

Delphi中多线程用消息实现VCL数据同步显示

Delphi中多线程用消息实现VCL数据同步显示 Lanno Ckeeke 2006-5-12 概述: delphi中严格区分主线程和子主线程,主线程负责GUI的更新,子线程负责数据运算,当数据运行完毕后,子线程可以向主线程式发送消息,以便通知其将VCL中的数据更新. 实现: 关键在于消息的发送及接收.在消息结构Tmessage中wParam和lParam类型为Longint,而指针类型也定义为Longint,可以通过此指针来传递自己所感兴趣的数据.如传递字符数组: 数组定义: const MA

ZeroMQ接口函数之 :zmq_msg_recv - 从一个socket中接受一个消息帧

ZeroMQ 官方地址 :http://api.zeromq.org/4-2:zmq_msg_recv zmq_msg_recv(3) ØMQ Manual - ØMQ/3.2.5 Name zmq_msg_recv - 从一个socket中接受一个消息帧 Synopsis int zmq_msg_recv (zmq_msg_t *msg, void *socket, int flags); Description zmq_msg_recv()函数和zmq_recvmsg(3)函数是完全相同的,

JS中模板嵌套学习(代码)

<script src="script/jquery-1.4.2.js"></script>    <script src="script/jsrender.js"></script>    <script id="header" type="text/x-jsrender">        <tr>               <th>序号&

Android中RecyclerView嵌套RecyclerView或嵌套ListView

Android中RecyclerView嵌套RecyclerView或嵌套ListView

C++ 中的嵌套类和局部类

C++ 中的嵌套类和局部类 最近趁着春节假期空闲,找了本C++ Primer 学了几章,发现C++ 中的许多特性自己都不知道.其中嵌套类和局部类感觉还是蛮有用的,简单的写写他们的用法. 嵌套类 所谓嵌套类就是可以在一个类中定义另一个类.这个被嵌套的类的作用域就只在它的上一级类中.下面是个例子: #include <iostream> using namespace std; class c1 { public: int a; void foo(); class c2 { public: int

crm组织服务中的xRM消息

Microsoft.Xrm.Sdk.Messages 命名空间支持用于处理任何实体中所存储的数据的核心消息.此命名空间还包含可用来检索和自定义实体.属性和关系的元数据的消息. 这些消息可与 IOrganizationService.Execute 方法一起使用.Microsoft.Xrm.Sdk.Messages 命名空间中可用的所有消息适用于所有三种部署类型. 请求页面指出消息在联机(连接到服务器)或脱机(与服务器断开连接)时是否能够正常工作 crm组织服务中的xRM消息,布布扣,bubuko