自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

API這樣設(shè)計(jì)?等著程序掛掉吧!

開發(fā) 架構(gòu)
假設(shè)提供的接口的入?yún)⒈容^復(fù)雜,可能有人會(huì)考慮使用結(jié)構(gòu)體作為入?yún)?。?dāng)你考慮這么做的時(shí)候,災(zāi)難也將會(huì)隨之而來……

[[351273]]

本文轉(zhuǎn)載自微信公眾號(hào)「編程珠璣」,作者守望先生。轉(zhuǎn)載本文請聯(lián)系編程珠璣公眾號(hào)。  

假設(shè)提供的接口的入?yún)⒈容^復(fù)雜,可能有人會(huì)考慮使用結(jié)構(gòu)體作為入?yún)ⅰ.?dāng)你考慮這么做的時(shí)候,災(zāi)難也將會(huì)隨之而來……

示例:

  1. // 來源:公眾號(hào)【編程珠璣】 
  2. // 作者:守望先生 
  3. // api.h 
  4. #include<iostream> 
  5. struct Param{ 
  6.     int num; 
  7.     std::string str; 
  8. }; 
  9. void TestFun(const Param &param); 
  10.  
  11. // api.cc 
  12. #include "api.h" 
  13. void TestFun(const Param &param){ 
  14.     std::cout<<"num:"<<param.num<<" str:"<<param.str.c_str()<<std::endl; 

假設(shè)提供TestFun作為一個(gè)對外接口,我們編譯并制作為靜態(tài)庫:

  1. $ g++ -c api.cc -I./ 
  2. $ ar -rcs libapi.a api.o  

關(guān)于靜態(tài)庫的制作,請參考《Linux下如何制作靜態(tài)庫?》。

另外一個(gè)程序main.cc這么使用它:

  1. // 來源:公眾號(hào)編程珠璣 
  2. // 作者:守望先生 
  3. #include "api.h" 
  4. int main(){ 
  5.     Param param; 
  6.     param.num = 10; 
  7.     param.str = "24";  
  8.     TestFun(param); 
  9.     return 0; 

編譯鏈接使用:

  1. $ g++ -o main main.cc -L./ -lapi -I ./ 
  2. $ ./main 

看起來并沒有什么問題,有新的參數(shù),可以直接在Param中增加即可,擴(kuò)展性也不錯(cuò)。

問題來了

目前來看是沒有什么問題的,但是假設(shè),還有另外一個(gè)庫要使用它,例如:

  1. // 來源:公眾號(hào)編程珠璣 
  2. // 作者:守望先生 
  3. // use_api.h 
  4. #include"api.h" 
  5. void UseApi(); 
  6.  
  7. // use_api.cc 
  8. #include"use_api.h" 
  9. void UseApi(){ 
  10.     Param param; 
  11.     param.num = 10; 
  12.     param.str = "24";  
  13.     TestFun(param); 

也將它作為靜態(tài)庫:

  1. $ g++ -c use_api.cc -I./ 
  2. $ ar -rcs libuse_api.a use_api.o  

這個(gè)時(shí)候同樣主程序會(huì)用到我們的原始api,但是卻使用了不同的版本,比如,新增了Param中新增了一個(gè)字段ext:

  1. // 來源:公眾號(hào)【編程珠璣】 
  2. // 作者:守望先生 
  3. // api.h 
  4. #include<iostream> 
  5. struct Param{ 
  6.     int num; 
  7.     std::string str; 
  8.     std::string ext; 
  9. }; 
  10. void TestFun(const Param &param); 
  11.  
  12. // api.cc 
  13. #include "api.h" 
  14. void TestFun(const Param &param){ 
  15.     std::cout<<"num:"<<param.num<<" str:"<<param.str.c_str()<<" ext:"<<param.ext.c_str()<<std::endl; 

重新生成靜態(tài)庫:

  1. $ g++ -c api.cc -I./ 
  2. $ ar -rcs libapi.a api.o  

這個(gè)時(shí)候,通過use_api使用api接口,但是鏈接新的庫:

  1. // 來源:公眾號(hào)編程珠璣 
  2. // 作者:守望先生 
  3. #include "use_api.h" 
  4. int main(){ 
  5.     UseApi(); 
  6.     return 0; 

這個(gè)時(shí)候,再去編譯鏈接,并運(yùn)行:

  1. $ g++ -o main main.cc -I./ -L./ -luse_api -lapi 
  2. $ ./main 
  3. Segmentation fault (core dumped) 

看到?jīng)]有,喜聞樂見的core dumped了,分析core還會(huì)發(fā)現(xiàn),是由于訪問非法地址導(dǎo)致的。

我們再來梳理一下這個(gè)過程:

  • 提供庫libapi.a版本A
  • libuse_api使用版本A進(jìn)行編譯,使用A版本的頭文件
  • libapi.a庫升級到B版本,其中頭文件中增加了字段,并且實(shí)現(xiàn)也引用了新的字段
  • 主程序使用了use_api,但是鏈接了版本B的libapi.a庫

這個(gè)時(shí)候,版本B的實(shí)現(xiàn)訪問了新的字段,還是use_api中還是使用A版本,并沒有傳入新字段,因此自然會(huì)導(dǎo)致非法訪問。

如何解決?

很簡單,不直接暴露成員,而是提供setter和getter,而提供方式和前面提到的PIMPL方法類似。

  1. // api.h 
  2. // 來源:公眾號(hào)編程珠璣 
  3. // 作者:守望先生 
  4. #include<iostream> 
  5. #include<memory> 
  6. class Param{ 
  7. public
  8.     void SetNum(int num); 
  9.     int GetNum() const; 
  10.     void SetStr(const std::string &str); 
  11.     std::string GetStr() const; 
  12.     void SetExt(const std::string &str); 
  13.     std::string GetExt() const; 
  14.     Param(); 
  15.   private: 
  16.     class ParamImpl; 
  17.     std::unique_ptr<ParamImpl> param_impl_; 
  18. }; 
  19. void TestFun(const Param &param); 

在這里頭文件中只提供setter和getter,而完全不暴露成員,具體成員的設(shè)置在ParamImpl中實(shí)現(xiàn):

  1. // api.cc 
  2. // 來源:公眾號(hào)編程珠璣 
  3. // 作者:守望先生 
  4. #include "api.h" 
  5. class Param::ParamImpl{ 
  6.   public
  7.     int num; 
  8.     std::string str; 
  9.     std::string ext; 
  10. }; 
  11. Param::Param(){ 
  12.     param_impl_.reset(new ParamImpl); 
  13. // 析構(gòu)函數(shù)必須要 
  14. Param::~Param() = default
  15. void Param::SetNum(int num){ 
  16.     param_impl_->num = num; 
  17. int Param::GetNum() const { 
  18.     return  param_impl_->num; 
  19. void Param::SetStr(const std::string &str){ 
  20.     param_impl_->str = str; 
  21. void Param::SetExt(const std::string &ext){ 
  22.     param_impl_->ext = ext; 
  23. std::string Param::GetStr() const { 
  24.     return param_impl_->str; 
  25. std::string Param::GetExt() const { 
  26.     return param_impl_->ext; 
  27. void TestFun(const Param &param){ 
  28.     std::cout<<"num:"<<param.GetNum()<<" str:"<<param.GetStr().c_str()<<"ext:"<<param.GetExt().c_str()<<std::endl; 

通過上面的方式,不會(huì)直接暴露成員函數(shù),而是提供接口設(shè)置或者獲取,而在實(shí)現(xiàn)中,即便出現(xiàn)新的版本增加了接口,最多也只是獲取到默認(rèn)值,而不會(huì)導(dǎo)致程序崩潰。

總結(jié)

本文和之前的文章實(shí)現(xiàn)方法是一樣的,這樣不暴露成員的做法,更大程度避免了鏈接庫不一致導(dǎo)致的問題,你學(xué)會(huì)了嗎?

作者:守望,linux應(yīng)用開發(fā)者,目前在公眾號(hào)【編程珠璣】?分享Linux/C/C++/數(shù)據(jù)結(jié)構(gòu)與算法/工具等原創(chuàng)技術(shù)文章和學(xué)習(xí)資源。

原文鏈接:https://mp.weixin.qq.com/s/3SmRDVzDq6NCBTeVPTwiWQ

 

責(zé)任編輯:武曉燕 來源: 編程珠璣
相關(guān)推薦

2010-07-16 11:12:40

云計(jì)算爭議

2013-12-09 09:35:04

Amazon云存儲(chǔ)

2024-02-22 00:09:00

開發(fā)代碼

2024-09-14 12:51:04

2022-12-26 18:53:00

MQ宕機(jī)倉儲(chǔ)服務(wù)

2013-06-07 08:42:38

游戲設(shè)計(jì)

2020-12-04 06:30:58

優(yōu)化性能指標(biāo)

2025-04-11 08:10:45

React模式Code

2012-03-27 09:20:57

Java

2018-06-25 13:37:13

2016-03-29 09:59:11

JavaScriptAPI設(shè)計(jì)

2012-02-09 09:08:41

Java

2013-03-28 15:50:37

程序員Java

2019-09-19 09:18:02

API網(wǎng)關(guān)互聯(lián)網(wǎng)

2018-06-28 08:40:23

Raid機(jī)械硬盤

2020-05-22 10:00:08

數(shù)據(jù)庫數(shù)據(jù)庫設(shè)計(jì)軟件設(shè)計(jì)

2023-01-05 09:33:38

低代碼高性能引擎

2012-07-20 10:32:32

程序員

2020-11-18 09:37:07

程序員技術(shù)996

2014-03-06 10:04:24

APIAWSOpenStack
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)