問題:跨dll,針對vector引用的傳遞沒有問題,但是map就出現問題了。
原因分析:
一句話-----如果任何stl類使用了靜態變數(無論是直接還是間接使用),那麼就不要再寫出跨執行單元訪問它的**。 除非你能夠確定兩個動態庫使用 的都是同樣的stl實現,比如都使用vc同一版本的stl,編譯選項也一樣。強烈建議,不要在動態庫介面中傳遞stl容器!!
stl不一定不能在dll間傳遞,但你必須徹底搞懂它的內部實現,並懂得為何會出問題。
微軟的解釋:
微軟給的解決辦法:
1、微軟的解釋:
大部分c++標準庫里提供的類直接或間接地使用了靜態變數。由 於這些類是通過模板擴充套件而來的,因此每個可執行映像(通常是.dll或.exe檔案)就會存在乙份只屬於自己的、給定類的靜態資料成員。當乙個需要訪問這 些靜態成員的類方法執行時,它使用的是「這個方法的**當前所在的那份可執行映像」裡的靜態成員變數。由於兩份可執行映像各自的靜態資料成員並未同步,這 個行為就可能導致訪問違例,或者資料看起來似乎丟失或被破壞了。
可能不太好懂,我舉個例子:假如類a有個靜態變數m_s,那麼當1.exe使用了2.dll中提供的某個a物件時,由於模板擴充套件機制,1.exe和2.dll中會分別存在自己的乙份類靜態變數a.m_s。
這樣,假如1.exe中從2.dll中取得了乙個的類a的例項物件a,那麼當在1.exe中直接訪問a.m_s時,其實訪問的是 1.exe中的對應拷貝(正確情況應該是訪問了2.dll中的a.m_s)。這樣就可能導致非法訪問、應當改變的資料沒有改變、不應改變的資料被錯誤地更 改等異常情形。
原文:1、保證資源的分配/刪除操作對等並處於同乙個執行單元;
比如,可以把這些操作(包括構造/析構函式、某些容器自動擴容時的記憶體再分配等)隱藏到介面函式裡面。換句話說:盡量不要直接從dll中輸出stl物件;如果一定要輸出,給它加上一層包裝,然後輸出這個包裝介面而不是原始介面。
2、保證所有的執行單元使用同樣版本的stl執行庫。
比如,全部使用release庫或debug庫,否則兩個執行單元擴充套件出來的stl類的記憶體布局就可能會不一樣。
只要記住關鍵就是:如果任何stl類使用了靜態變數(無論是直接還是間接使用),那麼就不要再寫出跨執行單元訪問它的**。
解決方法:
1. 乙個可以考慮的方案
比如有兩個動態庫l1和l2,l2需要修改l1中的乙個map,那麼我在l1中設定如下介面
int modify_map(int key, int new_value);
如果需要指定「某乙個map」,則可以考慮實現一種類似於控制代碼的方式,比如可以傳遞乙個dword
不過這個dword放的是乙個位址
那麼modify_map就可以這樣實現:
int modify_map(dword map_handle, int key, int new_value)
map_handle的值也首先由l1「告訴」l2:
dword get_map_handle();
l2可以這樣呼叫:
dword h = get_map_handle();
modify_map(h, 1, 2);
2. 加入乙個額外的層,就可以解決問題。所以,你需要將你的map包裝在dll內部,而不是讓它出現在介面當中。動態庫的介面越簡單越好,不好去傳太過複雜的東東是至理名言:)
from:
跨dll訪問STL的map的問題
問題 跨dll,針對vector引用的傳遞沒有問題,但是map就出現問題了。原因分析 一句話 如果任何stl類使用了靜態變數 無論是直接還是間接使用 那麼就不要再寫出跨執行單元訪問它的 除非你能夠確定兩個動態庫使用 的都是同樣的stl實現,比如都使用vc同一版本的stl,編譯選項也一樣。強烈建議,不...
STL 中 map 的用法
說明 如果你具備一定的 c template知識,即使你沒有接觸過stl,這個文章你也應該可能較輕易的看懂。本人水平有限,不當之處,望大家輔正。一 map概述 map是stl的乙個關聯容器,它提供一對一 其中第乙個可以稱為關鍵字,每個關鍵字只能在map中出現一次,第二個可能稱為該關鍵字的值 的資料處...
stl中map的使用
map與set類似,都是乙個關聯式容器,但是與set不同的是他鍵值分離的,key,value 結構,在map結構中元素是不允許重複的。在學習的過程中,我們需要主要一些問題 就是在關聯式容器中,當資料很大的時候,使用其中的查詢演算法是很快速的,應該使用其提供的函式來實現查詢函式等等高,會比使用stl中...