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

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

 

message PlayerPos{
required uint32 playerID = 1;
required float posX = 2 ;
required float posY = 3 ;
}

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

 

 

file  vector.proto

message  vector3D{
required float x = 1;
required float y = 2;
required float z = 3;
}; file Player.proto import "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 中的嵌套消息的使用的更多相关文章

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

    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. Linux进程管理命令

    CentOS默认并没有安装上psmisc这个软件包,就是像pstree,fuser这类的命令就没有了.如果想要执行这些命令最好的方法就是手动的去安装它们 解决方法: yum -y install ps ...

  2. C语言入门(1)——C语言概述

    1.程序与编程语言 我们使用计算机离不开程序,程序告诉计算机应该如何运行.程序(Program)是一个精确说明如何进行计算的指令序列.这里的计算可以是数学运算,比如通过一些数学公式求解,也可以是符号运 ...

  3. Crossing River poj1700贪心

    题目描述:N个人过河,只有一只船,最多只能有两人划船,每个人划船速度不同,船速为最慢的人的速度.输入T为case个数,每个case输入N为人数,接下来一行输入的是每个人过河的时间,都不相同.要求输出N ...

  4. poj2017简单题

    #include <stdio.h> #include <stdlib.h> int main() { int n,i; while(scanf("%d", ...

  5. Mac 域名解析

    1. 域名解析 如,解析 www.baidu.com 在终端输入, host www.baidu.com 题外话: 转载自:http://hoarn.blog.51cto.com/1642678/14 ...

  6. golang 之 defer(统计函数执行时间)

    package main import ( "fmt" "time" ) func sum(a ...int) int { defer trace(" ...

  7. 总结:C#变量,占位符等相关知识

    新年耽误了不少时间,好久没认真的坐下来学习了,新年也快完了,又要开始正式学习了,按着视频教学学习,用了一天的时间,学习了下简单的变量及其相关的输入输出和应用,学了几种最基本的类型: int(整型) c ...

  8. node.js的一些知识

    什么是node.js node.js是构建于chrome浏览器v8引擎上的一个js运行环境 可以解析和执行js代码 可以当做另一种上下文,脱离浏览器环境(后端)运行js代码,而代码解析就是基于V8引擎 ...

  9. CSS Sprite小图片自动合并工具

    css-sprite是将css样式中零星的小图标,小图片合并成大图显示,这样能减小服务器并发连接数,减小服务器负载和带宽使用,有很高的实用价值.这里介绍一些自动合并图片并生成样式的工具. NodeJS ...

  10. android 监听 USB 拔插广播消息

    USBBroadcastReceiver.java package com.example.communication; import android.content.BroadcastReceive ...