Microsoft + template + DLL = kłopoty
Wyobraźmy sobie, że tworzymy bibliotekę dzieloną (na Windows DLL), w której tworzymy obiekt będący instancją jakiegoś template zawierającego składowe statyczne (ot, choćby vector<string>) i chcemy przekazać tenże obiekt gdzieś na zewnątrz naszej biblioteki (albo na odwrót, otrzymujemy taki obiekt z zewnątrz).
Kilka przykładów takich sytuacji:
- tworzymy obiekt posiadający metodę const vector<string>& readKeys();
- albo robimy funkcję void readSth(vector<string>& param);
- albo funkcję void doSthElse(map<string,int> param);
- albo metodę map<int,int>::iterator myBegin().
Albo nawet nie wsadzamy nic takiego do API biblioteki ale robimy metodę inline w której wnętrzu operujemy na obiekcie takiego typu, np.
// Wewnątrz deklaracji klasy XXX map<string, int> m_someMap; // ... void SetParam(const string& key, int val) { m_someMap.insert(make_pair(key, val)); }
(kod metody zostanie rozwinięty i skompilowany w ramach kodu wołającego modułu - choć nie zawsze, niekiedy tylko w wersji release).
Nasz przyjaciel Microsoft (Visual C++) gwarantuje nam w każdej z tych sytuacji, w chwili wywołania odpowiedniej metody przez główny program lub inną bibliotekę, wygenerowanie gwałtu pamięci.
Co więcej jest to "by design". Opis znajduje się w MSDN jako:
PRB: Access Violation When Accessing STL Object in DLL Last reviewed: August 18, 1997 Article ID: Q172396
Sugerowane w tym dokumencie obejście to instancjonowanie eksplicite naszych template i eksportowanie ich z tworzonej biblioteki (gorzej gdy zrobią to niezależnie dla tego samego template autorzy dwóch niezależnych bibliotek). Można też oczywiście starannie usuwać wszelkie tego typu odwołania z API bibliotek i zamieniać metody inline na normalne.
Pozwolę sobie zacytować ostateczny komentarz kolegi, który stracił na badanie o co chodzi bodajże
paręnaście dni i zdiagnozował ten problem:
Nie nam k...a żyje M$ ^$%^#^%^&$%&$&@#$& !!!!!!
Uwaga końcowa: nie ma takich problemów z np. standardowym stringiem (który też jest rozwinięciem template basic_string) - jego sam Microsoft odpowiednio wyeksportował z biblioteki standardowej.
- «Metody statyczne bywają mylące
- Jak odróżnić platformę kompilacji»
- ↑C++ - sztuczki i niebezpieczeństwa