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

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

  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抽出来成为一个复合数据类型,单独放在一个文件中。这样就构成以下文件。

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

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

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

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

  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开头的,看看这个函数是干嘛的。

  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() 进行赋值看一看

  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的源码,发现一个问题

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

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

  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()

  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中又实现了赋值的重载,因此可以这样解决:

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

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

  1. protobuf 中的嵌套消息的使用

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

  2. google protobuf 中的proto文件编写规则

    1. 简单介绍 protobuf文件:就是定义你要的消息(类似Java中的类)和消息中的各个字段及其数据类型(类似java类中的成员变量和他的数据类型) 2. Protobuf消息定义 消息由至少一个 ...

  3. protobuf中的编码规则

    protobuf中的编码规则 (1)序列化和反序列化: 在开始本部分的内容之前,首先有必要介绍两个基本概念,一个是序列化,一个是反序列化.这两个概念的定义在网上搜一下都很多的,但大多都讲得比较晦涩,不 ...

  4. 使用自己的Python函数处理Protobuf中的字符串编码

    我目前所在的项目是一个老项目,里面的字符串编码有点乱,数据库中有些是GB2312,有些是UTF8:代码中有些是GBK,有些是UTF8,代码中转来转去,经常是不太清楚当前这个字符串是什么编码,由于是老项 ...

  5. 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_ ...

  6. 在WPF中处理Windows消息

    在Winform中 处理Windows消息通过重写WndProc方法 在WPF中 使用的是System.Windows. Sytem.Windows.Controls等名字空间,没有WndProc函数 ...

  7. 如何在项目中引入MetaQ消息收发机制

    当需要异步发送和接收大量消息时,需要在Crystal项目中引入MetaQ消息收发机制. 关于MetaQ使用的官方例子可参考:https://github.com/killme2008/Metamorp ...

  8. 【JS中循环嵌套常见的六大经典例题+六大图形题,你知道哪几个?】

    首先,了解一下循环嵌套的特点:外层循环转一次,内层循环转一圈. 在上一篇随笔中详细介绍了JS中的分支结构和循环结构,我们来简单的回顾一下For循环结构: 1.for循环有三个表达式,分别为: ①定义循 ...

  9. 微信小程序中发送模版消息注意事项

    在微信小程序中发送模版消息 参考微信公众平台Api文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#模版消息管理 此参考地址 ...

随机推荐

  1. Python 装饰器执行顺序迷思

    Table of Contents 1. 探究多个装饰器执行顺序 1.1. 疑问 1.2. 函数和函数调用的区别 1.3. 装饰器函数在被装饰函数定义好后立即执行 1.4. 疑问的解释 2. 参考资料 ...

  2. FastJson 打Release 包解析失败

    debug 的时候,fastJson 解析数据正常.但是打了release 的时候,解析的List 总是null. 找了半天,发现,是fastJson 是对泛型有问题. 解决办法: -keepattr ...

  3. javascript 数组的常用方法总结

    前言 主要讨论一下数组的方法,     1.splice和slice的区别     2.pop和push     3.shift和unshift     4.join     5.forEach(es ...

  4. 使用pip命令报You are using pip version 9.0.3, however version 18.0 is available pip版本过期.解决方案

    使用pip命令安装或卸载第三方库时报You are using pip version 9.0.3, however version 18.0 is available.错误,一般情况下是pip版本过 ...

  5. NOIP2018 集训(三)

    A题 Tree 问题描述 给定一颗 \(n\) 个点的树,树边带权,试求一个排列 \(P\) ,使下式的值最大 \[\sum_{i=1}^{n-1} maxflow(P_i, P_{i+1}) \] ...

  6. diskimage-builder-command

    yum -y install python-virtualenv.noarch virtualenv ~/dib-virtualenv . ~/dib-virtualenv/bin/activate ...

  7. Codeforces 1093G题解(线段树维护k维空间最大曼哈顿距离)

    题意是,给出n个k维空间下的点,然后q次操作,每次操作要么修改其中一个点的坐标,要么查询下标为[l,r]区间中所有点中两点的最大曼哈顿距离. 思路:参考blog:https://blog.csdn.n ...

  8. OpenFlow-Enaling innvation in Campus Networks

    OpenFlow-Enaling innvation in Campus Networks 出现问题 背景 Networks have become part of the critical infr ...

  9. PAT 甲级 1037 Magic Coupon

    https://pintia.cn/problem-sets/994805342720868352/problems/994805451374313472 The magic shop in Mars ...

  10. JavaScript中的parseInt和Number函数

    函数作用: parseInt将字符串(String)类型转为整数类型. Number() 函数把对象(Object)的值转换为数字. 语法不同: parseInt(string, [radix]) s ...