<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          調(diào)試實戰(zhàn) | 缺少 const 導致的 bug

          共 3549字,需瀏覽 8分鐘

           ·

          2021-03-31 18:11

          前言

          最近,在項目里遇到一個很 “詭異” 的問題。明明把后面需要使用的值存起來了,可是使用的時候,卻拿到了一堆垃圾數(shù)據(jù)。有可能是什么原因呢?一起來看看吧。

          調(diào)查思路

          這種問題排查起來比較簡單??梢砸来闻挪橐韵聨讉€地方:

          1. 保存代碼是否正確。
          2. 讀取代碼是否正確。
          3. 在保存后,讀取前是否有其它代碼修改了保存的值。

          按照這個思路,很快定位到問題出在第一步,也就是保存的時候出了問題。

          為了讓各位小伙伴兒也能實際感受這個問題,我特意模仿實際項目中的代碼寫了一份可以重現(xiàn)的代碼。

          關(guān)鍵代碼

          AdjustInfoByteConverter 里的代碼比較簡單,而且已經(jīng)驗證過沒問題,這就不貼了。感興趣的小伙伴兒可以下載示例工程查看完整代碼。

          調(diào)用代碼如下:

          #include?"stdafx.h"
          #include?"DemoObject.h"

          int?_tmain(int?argc,?_TCHAR*?argv[])
          {
          ????CDemoObject?object;
          ????AdjustInfo?info;
          ????auto?bytes?=?AdjustInfoByteConverter::ToBytes(info);
          ????object.SetAdjustInfo(bytes);

          ????//?in?real?project,?object?will?be?serialized,?and?deserialized.
          ????//?following?code?may?run?on?another?thread.
          ????std::vector<byte>?restoreBytes;
          ????object.GetAdjustInfo(restoreBytes);
          ????auto?info1?=?AdjustInfoByteConverter::FromBytes(restoreBytes);
          ????return?0;
          }

          說明:

          在實際排查問題的時候我就是這樣縮小排查范圍的,調(diào)用完 SetAdjustInfo(),直接調(diào)用 GetAdjustInfo(),查看兩次結(jié)果是否一致。這樣可以很快縮小需要排查的范圍。

          在寫完 AdjustInfoByteConverter::ToBytesAdjustInfoByteConverter::FromBytes 的實現(xiàn)后,也用了類似的辦法做了驗證,所以在實際項目中直接排除了這兩個函數(shù)的嫌疑。

          CDemoObject 類的實現(xiàn)如下,很規(guī)矩。

          #pragma?once
          #include?"ObjectProperty.h"
          #include?"AdjustInfo.h"
          #include?"AdjustInfoByteConverter.h"

          class?CDemoObject
          {

          private:
          ????ExtendPropertySet?extendProperty;

          public:
          ????void?SetAdjustInfo(const?std::vector<byte>&?bytes)
          ????
          {
          ????????PropertyValue?value(bytes);
          ????????extendProperty.SetSubParam("AdjustInfo",?value);
          ????}

          ????int?GetAdjustInfo(std::vector<byte>&?bytes)?const
          ????
          {
          ????????PropertyValue?value;
          ????????extendProperty.GetSubParam("AdjustInfo",?value);
          ????????bytes?=?value.m_value.m_valueByte;
          ????????return?(int)bytes.size();
          ????}
          };

          有瑕疵的代碼如下,但并不是所有情況下都有問題,你能找出這個問題嗎?

          #pragma?once
          #include?<vector>
          #include?<map>

          class?PropertyValue
          {

          public:
          ????enum?{?VALUENULL,?INT,?DOUBLE,?Bool,?String,?Block?}?m_type;
          ????PropertyValue()?:?m_type(VALUENULL)?{}

          ????struct
          ????{

          ????????std::vector<byte>?m_valueByte;
          ????}?m_value;

          ????template<class?T>
          ????PropertyValue(T?value)
          ????
          {
          ????????m_type?=?Block;
          ????????unsigned?__int32?nSize?=?sizeof(value);
          ????????byte?*data?=?(byte*)&value;
          ????????for?(unsigned?__int32?i?=?0;?i?<?nSize;?++i)
          ????????{
          ????????????m_value.m_valueByte.push_back((byte)(*(data?+?i)));
          ????????}
          ????}

          ????PropertyValue(std::vector<byte>&?value)
          ????{
          ????????m_type?=?Block;
          ????????m_value.m_valueByte?=?value;
          ????}
          };

          class?ExtendPropertySet
          {

          public:
          ????void?SetSubParam(const?std::string&?name,?PropertyValue?param)
          ????
          {
          ????????m_SubParamMap[name]?=?param;
          ????}

          ????bool?GetSubParam(const?std::string&?name,?PropertyValue&?param)?const
          ????
          {
          ????????auto?it?=?m_SubParamMap.find(name);
          ????????if?(it?!=?m_SubParamMap.end())
          ????????{
          ????????????param?=?it->second;
          ????????????return?true;
          ????????}
          ????????return?false;
          ????}

          private:
          ????std::map<std::string,?PropertyValue>??m_SubParamMap;
          };

          根本原因

          這個問題的根本原因在于:調(diào)用了錯誤的 PropertyValue 構(gòu)造函數(shù)。

          預期被調(diào)用的函數(shù)是 PropertyValue(std::vector<byte>& value),而實際調(diào)用的函數(shù)卻是 template<class T> PropertyValue(T value)。

          因為 CDemoObject 類的 void SetAdjustInfo(const std::vector<byte>& bytes) ?函數(shù)的參數(shù)是 const 的。在編譯 PropertyValue value(bytes); 這行代碼的時候,需要找到一個最優(yōu)的構(gòu)造函數(shù),最終找到的是 template 版本的。不能把一個 const 對象丟給一個參數(shù)是非 const 的函數(shù)!

          解決方案

          這個問題解決起來很簡單,有兩種改法:

          1. 去掉 const 對象的 const屬性。
          2. 改動底層代碼,把非 const 版本改成 const 版本的函數(shù)。

          實際項目中采用的第一種改法,因為沒有權(quán)限改動底層接口,但這種改法治標不治本。

          下載鏈接

          百度云盤鏈接: 鏈接: https://pan.baidu.com/s/1a2p9YWPLtlOe6dM_j_s80w 提取碼: j96h

          CSDN:https://download.csdn.net/download/xiaoyanilw/14965002

          總結(jié)

          • 盡量使用引用傳遞類對象,而且如果不想在函數(shù)內(nèi)部修改這個對象的話,務必加上 const
          • 不能把一個 const 對象丟給一個非 const 參數(shù)的函數(shù)。
          • 排查問題的時候,盡可能的縮小范圍。


          瀏覽 35
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩Aⅴ高清 | 69视频看黄片 | 亚洲初撮六十路老熟女 | 国产免费a | 啪啪视频自拍 |