protobuf 中的嵌套消息的使用 主要对set_allocated_和mutable_的使用
protobuf的简单的使用,不过还留下了一个问题,那就是之前主要介绍的都是对简单数据的赋值,简单数据直接采用set_xx()即可,但是如果不是简单变量而是自定义的复合类型变量,就没有简单的set函数调用了,下面看一个简单的例子。
在网络游戏中,游戏玩家之间的同步是一个最基本的功能,而同步是通过对坐标的广播进行的,因此我们假设一个简单的模型,当一个玩家的位置发生变化时,将玩家的新位置发给地图内所有玩家,根据这个情况写出以下proto文件。
- message PlayerPos
- {
- required uint32 playerID = 1;
- required float posX = 2 ;
- required float posY = 3 ;
- };
- file vector.protomessage vector3D
- {
- required float x = 1;
- required float y = 2;
- required float z = 3;
- };
这样就有一个问题,现在的游戏都是3D游戏,因此需要xyz来表示位置,还需要另一组xyz来表示朝向,如果用简单变量的话就会显的很乱,而且无论是位置还是朝向其实都是一组xyz,因此可以将xyz抽出来成为一个复合数据类型,单独放在一个文件中。这样就构成以下文件。
- file Player.protoimport "vector.proto";
- message PlayerPos
- {
- required uint32 playerID = 1;
- required vector3D pos = 2;
- };
编译的时候先编译vector文件,采用import时需要注意路径,本例中两文件在同一目录下。
- protoc --cpp_out=. vector.proto Player.proto
proto对应的文件已经生成了,但是该怎么赋值呢,查API查了半天有点不知所以,干脆来看生成的类文件的源代码吧
- // required uint32 playerID = 1;
- inline bool has_playerid() const;
- inline void clear_playerid();
- static const int kPlayerIDFieldNumber = 1;
- inline ::google::protobuf::uint32 playerid() const;
- inline void set_playerid(::google::protobuf::uint32 value);
- // required .vector3D pos = 2;
- inline bool has_pos() const;
- inline void clear_pos();
- static const int kPosFieldNumber = 2;
- inline const ::vector3D& pos() const;
- inline ::vector3D* mutable_pos();
- inline ::vector3D* release_pos();
- inline void set_allocated_pos(::vector3D* pos);
上面列出了生成的部分源代码,主要是PlayerPos的操作变量的函数,第一个playID很简单,可以看到直接使用set_playerid ( ) 即可,但是对于嵌套的pos 发现没有对应的set_pos方法,不过发现了一个set_allocated_pos() 函数,这个函数也是set开头的,看看这个函数是干嘛的。
- inline void PlayerPos::set_allocated_pos(::vector3D* pos)
- {
- delete pos_;
- pos_ = pos;
- if (pos)
- {
- set_has_pos();
- }
- else {
- clear_has_pos();
- }
- }
看上去可以赋值,直接调用set_allocated_pos() 进行赋值看一看
- PlayerPos player;
- vector3D tmp;
- tmp.x = 1;
- tmp.y = 2;
- tmp.z = 3;
- player.set_allocated_pos(&tmp)
编译没问题,但是运行时出现错误,而且是很奇怪的错误,仔细了查看一下PlayerPos的源码,发现一个问题
- ::vector3D* pos_; ::google::protobuf::uint32 playerid_;
上面是PlayerPos中变量的保存形式,发现pos是作为一个指针存储的,如果按照之前的赋值 tmp 是一个局部变量,函数返回时局部变量自动销毁,而pos_保存的仍然是已被销毁的tmp的位置,因此会出错,如果采用new的话就可以解决这个问题,即赋值方法如下:
- PlayerPos player;vector3D *tmp = new Vector3D;
- tmp->x = 1;
- tmp->y = 2;
- tmp->z = 3;
- player.set_allocated_pos(tmp)
这样即可,编译运行都没有问题。
如此之外,还有一种赋值方法,就是调用mutable_pos()
- inline ::vector3D* PlayerPos::mutable_pos()
- {
- set_has_pos();
- if (pos_ == NULL)
- pos_ = new ::vector3D;
- return pos_;
- }
mutable_pos () 中自己new出了一个vector3D 对象,而vector3D中又实现了赋值的重载,因此可以这样解决:
- PlayerPos player;
- vector3D *tmp = player.mutable_pos();
- tmp->x = 1;
- tmp->y = 2;
- tmp->z = 3;
protobuf 中的嵌套消息的使用 主要对set_allocated_和mutable_的使用的更多相关文章
- protobuf 中的嵌套消息的使用
protobuf的简单的使用,不过还留下了一个问题,那就是之前主要介绍的都是对简单数据的赋值,简单数据直接采用set_xx()即可,但是如果不是简单变量而是自定义的复合类型变量,就没有简单的set函数 ...
- google protobuf 中的proto文件编写规则
1. 简单介绍 protobuf文件:就是定义你要的消息(类似Java中的类)和消息中的各个字段及其数据类型(类似java类中的成员变量和他的数据类型) 2. Protobuf消息定义 消息由至少一个 ...
- protobuf中的编码规则
protobuf中的编码规则 (1)序列化和反序列化: 在开始本部分的内容之前,首先有必要介绍两个基本概念,一个是序列化,一个是反序列化.这两个概念的定义在网上搜一下都很多的,但大多都讲得比较晦涩,不 ...
- 使用自己的Python函数处理Protobuf中的字符串编码
我目前所在的项目是一个老项目,里面的字符串编码有点乱,数据库中有些是GB2312,有些是UTF8:代码中有些是GBK,有些是UTF8,代码中转来转去,经常是不太清楚当前这个字符串是什么编码,由于是老项 ...
- 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_ ...
- 在WPF中处理Windows消息
在Winform中 处理Windows消息通过重写WndProc方法 在WPF中 使用的是System.Windows. Sytem.Windows.Controls等名字空间,没有WndProc函数 ...
- 如何在项目中引入MetaQ消息收发机制
当需要异步发送和接收大量消息时,需要在Crystal项目中引入MetaQ消息收发机制. 关于MetaQ使用的官方例子可参考:https://github.com/killme2008/Metamorp ...
- 【JS中循环嵌套常见的六大经典例题+六大图形题,你知道哪几个?】
首先,了解一下循环嵌套的特点:外层循环转一次,内层循环转一圈. 在上一篇随笔中详细介绍了JS中的分支结构和循环结构,我们来简单的回顾一下For循环结构: 1.for循环有三个表达式,分别为: ①定义循 ...
- 微信小程序中发送模版消息注意事项
在微信小程序中发送模版消息 参考微信公众平台Api文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#模版消息管理 此参考地址 ...
随机推荐
- compileReleaseJavaWithJavac
如果你打release 包的时候,出现这个问题,那么请你先跑一下程序,肯定是有什么方法名,或者什么东西没找到. release 的时候不会报错,只有你跑的时候才会报错.
- 微信支付 h5
Android开发要点说明 商户在微信开放平台申请开发应用后,微信开放平台会生成APP的唯一标识APPID.由于需要保证支付安全,需要在开放平台绑定商户应用包名和应用签名,设置好后才能正常发起支付. ...
- LCS+LIS
#include<iostream> #include<string> using namespace std; string a,b; ][]; int main() { w ...
- BigDecimal简单说
1) 浮点数的舍弃规则: 假设小数点后保留两位 RoundingMode.CEILING:向正无穷大的方向舍入: 1.245 → 1.25 -1.245 → -1.24 RoundingMode ...
- appium 多个设备同时执行
测试需要同时在多个android设备上运行,就需要启动多个appium 使用adb命令获取udid,命令:adb get-serialno 使用的是testng测试框架,代码使用java编写 第一台, ...
- selenium + python之元素定位
selenium对web各元素的操作首先就要先定位元素,定位元素的方法主要有以下几种:通过id定位元素:find_element_by_id("id_vaule")通过name定位 ...
- shell监控脚本
序言: 前几天一好友问我服务器监控怎么做?你们公司的监控是怎么做的?有什么开源的监控软件推荐?常见的开源的监控软件当然首先推荐ZABBIX,分布式够强大,而且很多公司都在用,我问他具体什么需求,能监控 ...
- diskimage-builder-command
yum -y install python-virtualenv.noarch virtualenv ~/dib-virtualenv . ~/dib-virtualenv/bin/activate ...
- Leetcode 667.优美的排列II
优美的排列II 给定两个整数 n 和 k,你需要实现一个数组,这个数组包含从 1 到 n 的 n 个不同整数,同时满足以下条件: ① 如果这个数组是 [a1, a2, a3, ... , an] ,那 ...
- NodeJs03 express框架 Todo商城
前言 由于NodeJs本身的异步非阻塞特性和对http的天然支持,所以使用NodeJs编写高性能,可伸缩的Web服务器非常简单.开发完整的Web服务器还需要路由,错误处理,请求拦截,请求和响应的解析, ...