老胡最近在工做中,有個場景須要使用一個第三方庫,引用頭文件,連接庫,編譯運行,一切都很正常,可是接下來就遇到了一個很詭異的問題,調用該庫的中的一個對象方法爲對象修改屬性的時候,會影響到對象的另一個屬性,當時百思不得其解,直呼靈異事件。
但後面靜下心來細細看了一下代碼和各類配置,發現了問題所在,如今把這個問題分享在這裏,但願你們在之後的工做中若是遇到了相似的狀況知道應該如何處理。
ios
當時引用的是一個第三方的靜態連接庫,場景很是簡單,在項目中包含頭文件,連接器指定路徑和靜態庫名稱,咱們這裏新建工程來生成一個很是簡單的庫。
this
其中,spa
//LibObject.h #pragma once struct LibObject { int valueA{ 0 }; #ifdef AdditionalValue int valueB{ 0 }; #endif int valueC{ 0 }; void DoSomething(); }; //LibObject.cpp #include "LibObject.h" void LibObject::DoSomething() { valueA = 10; #ifdef AdditionalValue valueB = 10; #endif }
簡單至極,若預編譯變量定義了AdditionalValue則定義多一個valueB而且在方法中賦值。編譯庫的時候咱們指定AdditionalValue。
指針
//main.cpp #include "LibObject.h" #include <iostream> using namespace std; int main() { LibObject obj; cout << obj.valueA << endl; cout << obj.valueC << endl; obj.DoSomething(); cout << obj.valueA << endl; cout << obj.valueC << endl; return 0; }
客戶端代碼也很簡單,聲明一個對象,調用它的方法並在調用先後檢查它的值,在編譯客戶端代碼的時候,咱們不定義AdditionalValue預編譯變量。
code
如今猜一猜輸出是多少?對象
若是這個結果讓你吃驚,那麼相信我,你不是一我的,當時老胡也驚呆了,無論怎麼看,DoSomething僅僅修改了ValueA,爲何會讓ValueC的值變了?blog
祕密就在於編譯庫的時候和編譯客戶端代碼的時候,咱們使用了不一樣的預編譯變量。事件
因此答案揭曉了,爲何valueC的值會被影響,在於DoSomething執行的時候,至關於this指針偏移爲4的int被賦值了,可是在咱們從客戶端代碼構建的結構體中,這個位置存放的是valueC。內存
從這裏能夠看出,在方法執行的過程當中,所謂的valueB其實內存地址和valueC是同樣的。因此實際上是那句給valueB賦值的語句把值給了valueC。
文檔
知道了出問題的地方,修復起來就很簡單了,通常來講兩個辦法。
這兩個辦法都須要仔細閱讀第三方庫的文檔。 但願本文能給遇到了相似問題的小夥伴一點啓示,特別當你遇到了相似的狀況的時候,這篇文章可以給你一些思路,畢竟,編譯器甚至在這種狀況下都不會給出任何警告,咱們只能靠經驗排查了。