protobuf的簡單的使用,不過還留下了一個問題,那就是以前主要介紹的都是對簡單數據的賦值,簡單數據直接採用set_xx()便可,可是若是不是簡單變量而是自定義的複合類型變量,就沒有簡單的set函數調用了,下面看一個簡單的例子。網絡
在網絡遊戲中,遊戲玩家之間的同步是一個最基本的功能,而同步是經過對座標的廣播進行的,所以咱們假設一個簡單的模型,當一個玩家的位置發生變化時,將玩家的新位置發給地圖內全部玩家,根據這個狀況寫出如下proto文件。函數
message PlayerPos{ required uint32 playerID = 1; required float posX = 2 ; required float posY = 3 ; }
這樣就有一個問題,如今的遊戲都是3D遊戲,所以須要xyz來表示位置,還須要另外一組xyz來表示朝向,若是用簡單變量的話就會顯的很亂,並且不管是位置仍是朝向其實都是一組xyz,所以能夠將xyz抽出來成爲一個複合數據類型,單獨放在一個文件中。這樣就構成如下文件。ui
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時須要注意路徑,本例中兩文件在同一目錄下。google
protoc --cpp_out=. vector.proto Player.proto
proto對應的文件已經生成了,可是該怎麼賦值呢,查API查了半天有點不知因此,乾脆來看生成的類文件的源代碼吧
spa
// 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() 進行賦值看一看code
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;