2010-01-09 121 views
2

我正在使用Qt(gui lib),VTK(圖形庫)和另一個如此晦澀的庫的C++項目,我不會提及它的名稱,而是將其稱爲LIB_X。該項目使用QT爲gui組件和VTK(更確切地說是由VTK提供的支持Qt的QVTKWidget擴展)來渲染幾何體,並使用LIB_X來收集和處理幾何體。VC++庫衝突問題

問題是,事實證明,LIB_X實際上使用VTK(在哪裏以及如何,我不知道它是封閉的源代碼)。起初沒有問題,編譯兩個庫鏈接都很好,但在某些時候,我調用了一個(並且非常需要)LIB_X函數,並且編譯導致了一堆關於已經定義的VTK lib/obj的'blah blah'在LIB_X DLL'錯誤。

例如(並注意這與/ FORCE:多所以這是一個警告在這裏,讓我知道如果你想要的錯誤,而不/ FORCE:多,我會後):

1>LIB_X.lib(LIB_X.dll) : warning LNK4006: "public: __thiscall std::vector<double,class std::allocator<double> >::~vector<double,class std::allocator<double> >(void)" ([email protected][email protected]@[email protected]@@[email protected]@[email protected]) already defined in vtkCommon.lib(vtkInformationDoubleVectorKey.obj); 

我嘗試使用/ FORCE: MULTIPLE,它起初似乎是一個奇蹟,但是我得到的代碼中的隨機錯誤通常會導致堆錯誤。我決定從主項目中刪除對LIB_X的所有引用,並創建一個靜態庫來處理所有LIB_X的東西。我不是C++專家,所以我不確定在使用預編譯庫時它是如何處理庫衝突的,但是當我將靜態庫鏈接到我的主項目時仍然收到lib衝突錯誤,所以我仍然必須使用/ FORCE:MULTIPLE。

一旦我有了靜態庫,好像隨機錯誤消失了,我可以通過靜態庫在主項目中使用LIB_X方法做很多事情,但是無處不在,我添加了一個新的數據成員到我的主要項目的類(一個std ::向量的雙打),突然間我在我的一個靜態庫的方法中得到了一個堆錯誤。如果我註釋掉了新的數據成員,靜態庫的方法會運行良好。我討厭給當前的錯誤,因爲老實說,我不確定是否檢查它是值得的,但在這裏它是無論如何,以防萬一它可以幫助:

注意:它崩潰xutility約151行,彈出斷言: 「文件:dbgheap.c行:1279表達式:_CrtIsValidHeapPointer(pUserData)」

的錯誤出現添加矢量矢量雙到矢量矢量矢量雙,拍擊的push_back行之後:

std::vector<std::vector<double>> tmpVec; 
for(srvl_iter = srvl.begin(); srvl_iter != srvl.end(); ++srvl_iter) 
{ 
tmpVec.push_back((*srvl_iter).getControlPoints()); 
} 
this->_splines.push_back(tmpVec); //CRASH 

當我向主項目中添加一個新的數據成員時,它只在這裏崩潰(與靜態分開lib!)註釋掉新的數據成員會將錯誤消除。

std::vector<std::vector<std::vector<double>>> _geometry; 

因此,/ FORCE:MULTIPLE看起來不好,我得到的隨機錯誤對我來說沒有意義。還有其他解決方案嗎?我擰了嗎?有什麼我可以用LIB_X連接VTK做什麼?

回答

1

當我將應用程序鏈接到一個使用std::vector<std::string>的庫(稱爲庫LIB_Y)時,我遇到了一堆LNK4006錯誤,這也是我在我的應用程序中所做的。經過一番嘗試後,我發現了一個解決方案 - 將LIB_Y封裝在一個調用LIB_Y(LIB_Y_WRAPPER)的獨立DLL中,然後將主應用程序與LIB_Y_WRAPPER相關聯。

要嘗試一下我的建議,你將需要:

  1. 改變從靜態庫項目成一個DLL項目(我會打電話給LIB_X_WRAPPER)你的「處理所有LIB_X東西靜態庫」。
  2. 確保LIB_X_WRAPPER的頭文件不包含任何LIB_X頭文件。這是非常重要的,因爲包裝需要將您的應用程序與LIB_X頭文件中聲明的數據類型(如std::vector<double>)完全隔離。僅從LIB_X_WRAPPER的源文件中引用LIB_X的頭文件。
  3. 更改靜態庫中所有類和函數的聲明以確保它們從DLL中導出(如果需要有關從DLL導出的詳細信息,請參閱this answer)。

該解決方案爲我工作,因爲它一直由立白所使用的std::vector<std::string>類從std::vector<std::string>在我的應用程序的實例完全獨立的實例(編譯器生成的函數)。另外,我懷疑你看到的崩潰的原因(你評論它在std::vector<double>的析構函數中)是因爲你的應用中的std::vector<double>的實例化與LIB_X中的不同。

+0

我在想,如果這樣的事情能夠發揮作用,我會嘗試進行測試。 到目前爲止,我的問題是#2,從包裝中刪除libx頭。我需要libx中的數據成員在我的類中,他們需要libx命名空間來聲明。該變量可能看起來像Libx :: DataStructA _dataStructA;我無法創建類原型,因爲它需要名稱空間,而且我不能使用名稱空間,因爲我沒有頭部訪問,但是當涉及到可以解決此問題的名稱空間時,我可能不知道有什麼? – ferr 2010-01-10 18:33:24

+0

更多關於我上面的評論,我不確定它是否與名稱空間有關,它只是一個前向聲明問題,完全在很多級別上。我試圖轉發聲明的libx類沒有在我的類中聲明爲一個指針,所以它爲此提出了一個合適的解決方案。將它聲明爲指針似乎沒有多大幫助。 – ferr 2010-01-10 19:18:49

+0

好吧,在做了大量的搜索和搜索後,它看起來像你可以在類似這樣的命名空間中聲明一個類:namespace LibX {class libxClass; },這樣我可以稍後聲明一個LibX :: libxClass。我現在遇到的問題是我正在重新定義錯誤。我的.cpp文件中包含libxClass.h文件,它抱怨在我的頭文件和libxClass.h文件中有一個定義。最重要的是,我試圖轉發聲明的'class'實際上是一個類的typedef ..不知道對這種情況有什麼影響。 – ferr 2010-01-10 22:30:31

0

註釋可能只是隨機運氣 - 如果你正在破壞堆,你不會總是看到它,但一個stl向量將分配和釋放左右的事情,所以難怪它找到了錯誤。

一些庫需要你按照一定的順序包括東西。我不確定爲什麼,因爲我似乎放棄了,並說你不能正確設計一個圖書館,但這是一個可悲的事實。不過,只要你不包括這個lib_x在你包含vtk的地方,它應該沒問題。

但是,他們可能會爲某些資源而戰,或者使用不適當的方式使他們無法一起工作。如果你能夠通過隔離它們來使編譯工作正常,那麼它仍然會失敗,那麼你是不幸運的,因爲這只是一個失敗的方式,因爲這是lib_x的設計方式,因爲它很模糊,所以不太可能徹底調試所有用途。當某些東西沒有被廣泛使用時,它通常最終會成爲開發者的機器和項目上的一些東西,但不一定是其他人的東西。

+0

我認爲保持vtk和lib_x儘可能分開也會解決它。但我確實爲我的lib_x創建了一個靜態庫。我只在這個靜態庫中的lib_x庫中鏈接,當然在我的靜態庫中沒有vtk鏈接。我的主項目沒有鏈接任何lib_x庫,但鏈接到靜態庫暴露了vtk和lib_x衝突。 有沒有其他方法可以讓它們更加分離? 最後的手段是我爲lib_x製作一個單獨的應用程序,將所有輸出寫入文本文件。它會慢得多,但它可能是一個臨時解決方案。 – ferr 2010-01-09 21:32:26

+0

我一直在進一步研究它,我認爲現在可能很明顯,LIB_X和VTK都可能在爭奪資源。 如果您查看鏈接器錯誤,它指定問題與多次定義的std :: vector相關。我經歷了崩潰的調用堆棧,試圖釋放std :: vector之後崩潰了。崩潰的方法顯然是試圖釋放已經被釋放的東西。所以我猜想有兩件事是試圖釋放一個向量。 – ferr 2010-01-10 01:56:39

+0

那麼,你可以做的是編譯和運行它們都作爲完全獨立的進程,並通過IPC或內存映射等將數據發送給它。不幸的是,你不能僅僅把它全部放到extern中,並且單獨加載它,因爲它不會初始化靜態內容。在dll中,我認爲所有版本都有自己的靜態變量,所以如果你可以在單獨的dll中編譯它們呢?我不確定,通常我會像瘟疫一樣避開它們,也許別人會知道。 – 2010-01-10 10:06:15