Sziasztok!
C++ expertek véleményére lennék kíváncsi a következőkkel kapcsolatban:
Adott egy C++ programocska amely Visual studio 2008 alatt íródik, eredménye pedig egy DLL fájl lészen. Ez a DLL egy másik program plugin -ja, így az adott programhoz kapott .h és és .lib fájlokat kell használjam.
Csináltam egy fagolyó bonyolultságú osztályt TMocsing
, néhány változóval, set_xx() get_xx()
függvénnyel illetve egy std::vector bubu;
vektorral. A .h amiben az osztályt definiálom (mocsing.h) hivatkozik egy rakat plugin header -re illetve a
vector
-ra.
Abban a .cpp fájlban (csirkehus.cpp) ahol a mocsing.h -t include -olom, szintén vannak plugin headerek include -olva, valamint sokszoros include mélységben a vector
is.
Mármost, olyan pofára esésben volt részem, hogy csak na! Ugyanis a csirkehus.cpp -ben máshogy sikeredett leforduljon a vector
, mint a mocsing.cpp -ben. Ennek eredményeként a bubu.push_back()
rendszeresen bad_accoc kivételeket dobált, ugyanis a vector _Myfirst, _Mylast
és _Myend
mutatói az osztályon belül rossz offset -tel címződtek. Megoldás:
- mocsing.h -ban hivatkozni ugyanarra a .h -ra, amelyik csirkehus.cpp -ben a vectort include -olja
- csirkehus.cpp -ben
std::vector bubu;
változót létrehozni TMocsing bárminemű hivatkozása előtt.
Látott már valaki hasonlót?
Hozzászólások
DLL felületi header-be és osztályba soha ne tegyél STL könyvtári element. Oka: az egyes VS verziókban* az STL mérete változhat. Simán előfordulhat, hogy az STL-es osztályt használó könyvtár kevés memóriát allokál az STL-t tartalmazó, a DLL felületéről vett osztályodnak.
Tipikus meogoldás worker oszályt írni, ami tartalmazza az STL-es cuccaidat.
DLL headerben:
#pragma once
class exampleWorker;
#ifdef PROJECTNAME
#define projectEXPORT __declspec( dllexport )
#else
#define projectEXPORT __declspec( dllimport )
#endif
class projectEXPORT example
{
public:
example();
~example();
size_t size();
private:
exampleWorker * worker;
};
Cpp-ben:
#include "example.h"
#include <vector>
class exampleWorker
{
std::vector<int> store;
};
example::example(void)
: worker(new exampleWorker)
{
}
example::~example(void)
{
if ( this->worker )
{
delete this->worker;
this->worker = 0;
}
}
size_t example::size(void)
{
return this->worker->store.size();
}
Hasznos olvasni való. És ez is.
*: VS 2005 / 2005 SP1 / 2008 / 2008 SP1 / 2010 / 2010 SP1
--
http://naszta.hu
Na, rendesen rám ijesztettetek.... Egyelőre működik a dll de hosszabb távon rendbe kell tegyem ezt a dolgot :S Elképzelni sem merem mi lesz itt, ha más verziójú binárissal akarják majd használni. Majd hétfőn kiderül a prezentáción... ;)
Akárhogy is, köszönöm az okítást mindkettőtöknek. Most már el tudok indulni.
Ez csak akkor fog menni, ha pontosan ugyanazt a VS verziót használod amit a dll.
Nem csak a főverzió, de a Service Pack is számít, illetve az sem mindegy, hogy debug vagy release.
Welcome to the world of MS.
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
Azért tegyük hozzá, hogy ez nem bug, hanem feature. Mármint:
- az STL inline (tehát ahol használod, ott jó a teljesítménye),
- a bináris hosszú évekig hordozható, nem kell fordítgatni hetente. Gyakorlatilag egy VS 6.0 alatt fordított DLL-t is tudsz akár ma is használni.
Ennek az az ára, hogy az STL nincs DLL felületen. Együtt lehet élni ezzel a megkötéssel.
--
http://naszta.hu
Azért a gcc srácok megoldották valahogy, hogy ritkábban változzon az STL, és nincs is annyi szívás vele...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
Azért tegyük hozzá, hogy gcc alatt nem szempont a bináris kompatibilitás évekig. Többször fordult már elő, nem is egy distro-val, hogy a libc és a libc++ verzió váltást is csak fő disztró verzió váltáskor érvényesítettek, pont ebből az okból (hogy legalább a major disztro verzión belül legyen olyan, mintha szempont lenne a bináris kompatibilitás).
--
http://naszta.hu
"Ennek az az ára, hogy az STL nincs DLL felületen. Együtt lehet élni ezzel a megkötéssel."
Akkor már inkább megkötöm a fordító verziót... Egy-egy osztály esetén még lehet itt wrapperekkel bohóckodni, de egyébként esélytelen.
Nagyobb projectek is vagy megkötik a fordító verzióját (Qt), vagy több verziójú fordítóhoz is elkészítik a binárist. (TBB, OpenCV)
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
Meg egy apróság:
Ha
#include <istream>
-ot vagy>#include <ostream>
-ot szúrsz be ésstd::istream &is
vagystd::ostream &os
van az osztály felületén, azért nem károg a VS. Azt nem tudom, hogy mennyire átjárható, mert nem próbáltam, de kiváncsi lennék rá. (Pl.: tud egy VS 2005 SP1-es DLL normálisan menni a VS 2010 SP1-as környezetben?)--
http://naszta.hu
elirtad a cimet, std::vector-ra gondoltal gondolom
Köszi, javítva.