Access Violation with map<string,xxx>
Author |
Message |
Araga #1 / 11
|
 Access Violation with map<string,xxx>
Hello, My dll have a template Class: //##ModelId=3B4C5F6D00DF template<class T> class CSgDictionaryStringImpl : public CSgObject { public: CSgDictionaryStringImpl(); virtual ~CSgDictionaryStringImpl(); virtual T* getAt(const std::string& key) const; virtual Sag::ErrorStatus setAt(LPCTSTR key, T* pDictEntry); virtual Sag::ErrorStatus remove(const std::string& key); virtual Sag::ErrorStatus removeAll(); private: std::map< std::string, T* >* m_pMapDictEntry; Quote: };
and my setAt member function implementation is: template<class T> Sag::ErrorStatus CSgDictionaryStringImpl< T >::setAt(const std::string& key, T* pDictEntry) { (*m_pMapDictEntry)[key] = pDictEntry; return Sag::eOk; Quote: }
and my destructor call this member function: template<class T> Sag::ErrorStatus CSgDictionaryStringImpl< T >::removeAll() { std::map<std::string, T*>::iterator iteratorMap; while(!m_pMapDictEntry->empty()) { iteratorMap = m_pMapDictEntry->begin(); T* pObj = NULL; pObj = (*iteratorMap).second; delete pObj; pObj = NULL; iteratorMap = m_pMapDictEntry->erase (iteratorMap); } return Sag::eOk; Quote: }
When I unload my dll I have an access violation. But when I change my setAt member function, I didnt have any access violation: template<class T> Sag::ErrorStatus CSgDictionaryStringImpl< T >::setAt(const std::string& key, T* pDictEntry) { (*m_pMapDictEntry)[key.c_str()] = pDictEntry; return Sag::eOk; Quote: }
very strange. Anyone know how is the problem???????????????? Thanks, Aragao
|
Sun, 18 Jan 2004 02:32:57 GMT |
|
 |
Gonzalo Matama #2 / 11
|
 Access Violation with map<string,xxx>
Quote: > Hello, > My dll have a template Class: > //##ModelId=3B4C5F6D00DF > template<class T> > class CSgDictionaryStringImpl : public CSgObject > { > public: > CSgDictionaryStringImpl(); > virtual ~CSgDictionaryStringImpl(); > virtual T* getAt(const std::string& key) const; > virtual Sag::ErrorStatus setAt(LPCTSTR key, T* > pDictEntry); > virtual Sag::ErrorStatus remove(const std::string& > key); > virtual Sag::ErrorStatus removeAll(); > private: > std::map< std::string, T* >* m_pMapDictEntry; > };
<snip> Quote: > When I unload my dll I have an access violation. > But when I change my setAt member function, I didnt have > any access violation:
<snip> DLL and EXE don't share the same heap: Every one has its own heap. When you execute code in EXE, this code allocate or deallocate memory from EXE heap, and when you execute code from DLL, the DLL heap is used. In setAt() function, you pass pointer to objects created in EXE code (allocated in EXE heap), and in removeAll(), yo extract those pointer and delete thems from DLL code (deallocated from DLL heap). ?Is this the problem? Gonzalo.
|
Sun, 18 Jan 2004 16:16:50 GMT |
|
 |
Araga #3 / 11
|
 Access Violation with map<string,xxx>
Hi Gonzalo, In My Dll I have an Class Singleton: class SSAGREDLLIMPEXP CSgApp { public: static Sag::ErrorStatus registerApp(const std::string& strModuleName, CSgApp* pApp); virtual Sag::ErrorStatus initialize(); virtual Sag::ErrorStatus finalize(); static CSgApp* instance(); CSgDictionary* getMainDictionary(); Sag::ErrorStatus getModuleName(std::string& strModuleName); protected: CSgApp(); virtual ~CSgApp(); Sag::ErrorStatus setModuleName(const std::string& strModuleName); private: static CSgApp* m_pApp; //static member std::string m_strModuleName; CSgDictionary* m_pDict; Quote: };
/////////////////Arquivo CSgApp.cpp///////////////////// CSgApp* CSgApp::m_pApp = NULL; CSgApp::CSgApp() : m_strModuleName(""),m_pDict(NULL) { m_pDict = new CSgDictionary; Quote: }
Sag::ErrorStatus CSgApp::initialize() { return Sag::eOk; Quote: }
//##ModelId=3AC0CDDD036D Sag::ErrorStatus CSgApp::finalize() { delete m_pDict; //delete m_pApp; return Sag::eOk; Quote: }
CSgApp::~CSgApp() { Quote: }
Sag::ErrorStatus CSgApp::setModuleName(const std::string& strModuleName) { //m_strModuleName = strModuleName.c_str(); m_strModuleName = strModuleName; return Sag::eOk; Quote: }
Sag::ErrorStatus CSgApp::getModuleName(std::string& strModuleName) { strModuleName = m_strModuleName; return Sag::eOk; Quote: }
CSgDictionary* CSgApp::getMainDictionary() { return m_pDict; Quote: }
CSgApp* CSgApp::instance() { return m_pApp; Quote: }
Sag::ErrorStatus CSgApp::registerApp(const std::string& strModuleName, CSgApp* pApp) { if(m_pApp) return Sag::eAppWasCreated; m_pApp = pApp; m_pApp->setModuleName(strModuleName); return Sag::eOk; Quote: }
where m_pDict is derived from template<CSgObject> class CSgDictionaryStringImpl. Access violation happen on CSgDictionaryStringImpl<CSgObject>::removeAll() that is called on destructor ~CSgDictionaryStringImpl<CSgObject>. the member variable m_pDict is created on CSgApp constructor(on DLL???) On my EXE I have a Class CSgAcBasicApp derived from Singleton CSgApp: class CSgAcBasicApp : public CSgApp { public: virtual ~CSgAcBasicApp(); CSgAcBasicApp(); Quote: };
On My exe I have a factory that Create an instance of CSgAcBasicApp: Sag::ErrorStatus CSgAcBasicAppFactory::createApplication() { CSgAcBasicApp* pApp = new CSgAcBasicApp(); if(pApp == NULL) return Sag::eOutOfMemory; Sag::ErrorStatus es = CSgApp::registerApp ("Sagre/Cad", pApp); if(es != Sag::eOk) { delete pApp; return es; } return es; Quote: }
So, when I unload my Exe I call the virtual function CSgAcBasicApp::finalize() that was defined on CSgApp::finalize() and CSgApp::finalize just call the dictionary destructor. Really I Dont know what is happening. This is an STL limitation or I am making mistakes??? Thanks, Aragao Quote: >-----Original Message-----
Quote:
>> Hello, >> My dll have a template Class: >> //##ModelId=3B4C5F6D00DF >> template<class T> >> class CSgDictionaryStringImpl : public CSgObject >> { >> public: >> CSgDictionaryStringImpl(); >> virtual ~CSgDictionaryStringImpl(); >> virtual T* getAt(const std::string& key) const; >> virtual Sag::ErrorStatus setAt(LPCTSTR key, T* >> pDictEntry); >> virtual Sag::ErrorStatus remove(const std::string& >> key); >> virtual Sag::ErrorStatus removeAll(); >> private: >> std::map< std::string, T* >* m_pMapDictEntry; >> }; ><snip> >> When I unload my dll I have an access violation. >> But when I change my setAt member function, I didnt have >> any access violation: ><snip> >DLL and EXE don't share the same heap: Every one has its own heap. When >you execute code in EXE, this code allocate or deallocate memory from >EXE heap, and when you execute code from DLL, the DLL heap is used. >In setAt() function, you pass pointer to objects created in EXE code >(allocated in EXE heap), and in removeAll(), yo extract those pointer >and delete thems from DLL code (deallocated from DLL heap). >?Is this the problem? >Gonzalo. >.
|
Sun, 18 Jan 2004 20:41:12 GMT |
|
 |
Gonzalo Matama #4 / 11
|
 Access Violation with map<string,xxx>
I'm almost sure the problem is copying strings. ??Warning!! STL strings are referenced. When you copy a string: string a(b); both reference the same string and a counter is incremented. When the destructor is invoked, de counter is decremented, and the las destructor free the memory. When you pass a string from EXE to DLL, if string is copied, DLL don't alloc memory: setAt(const string& key) { my_map[key] = something; // the string is not copied, but // incremented reference Quote: }
But if you dont use more the string in EXE, the destructor is invoked and the reference is decremented. If DLL code is the last invoking string destructor: removeAll() { my_map.erase(my_map.begin()); // the element destructor in map is // invoked, the key destructor is // invoked too. Quote: }
if is the last instance of string, string::~string() try dealloc memory from its heap: Access Violation!! ?What is the solution? Don't use STL static link, use STL dynamic link. Both code, EXE and DLL will use STL in MSVCRT.DLL (I don't remember the exact name), the constructor and destructor code of string will in the same location. In your projects settings you can specify you want link dynamic runtime libs. Perhaps you need define macro EXP_STL in your settings too. Gonzalo.
|
Mon, 19 Jan 2004 18:11:41 GMT |
|
 |
Araga #5 / 11
|
 Access Violation with map<string,xxx>
Hi Gonzalo, Thanks for your reply. I think that this is the problem. To say the truth, I didnt have One exe and one dll, but 2 dlls. My Application is a third part application(run on Autocad- cad product-acad.exe), so I have two dlls that run on acad.exe. To build dlls that run on Autocad I have to use a pre defined project configuration. For exemple I have to use the option "Multithreaded DLL"(Applications compiled with this option are statically linked to MSVCRT.LIB). So I dont know how can I solve this problem yet. PS: I am using the EXP_STL macro. Cheers, Aragao Quote: >-----Original Message-----
>I'm almost sure the problem is copying strings. >??Warning!! STL strings are referenced. When you copy a string: >string a(b); >both reference the same string and a counter is incremented. >When the destructor is invoked, de counter is
decremented, and the las Quote: >destructor free the memory. >When you pass a string from EXE to DLL, if string is copied, DLL don't >alloc memory: >setAt(const string& key) >{ > my_map[key] = something; // the string is not copied, but > // incremented reference >} >But if you dont use more the string in EXE, the
destructor is invoked Quote: >and the reference is decremented. >If DLL code is the last invoking string destructor: >removeAll() >{ > my_map.erase(my_map.begin()); // the element
destructor in map is Quote: > // invoked, the key destructor is > // invoked too. >} >if is the last instance of string, string::~string() try dealloc memory >from its heap: Access Violation!! >?What is the solution? Don't use STL static link, use STL dynamic link. >Both code, EXE and DLL will use STL in MSVCRT.DLL (I don't remember the >exact name), the constructor and destructor code of string will in the >same location. In your projects settings you can specify you want link >dynamic runtime libs. >Perhaps you need define macro EXP_STL in your settings too. >Gonzalo. >.
|
Mon, 19 Jan 2004 19:35:57 GMT |
|
 |
Gonzalo Matama #6 / 11
|
 Access Violation with map<string,xxx>
Quote: > To build dlls that run on Autocad I have to use a pre > defined project configuration. For exemple I have to use > the option "Multithreaded DLL"(Applications compiled with > this option are statically linked to MSVCRT.LIB). > So I dont know how can I solve this problem yet. > PS: I am using the EXP_STL macro. > Cheers, > Aragao
Miltihreaded DLL link to MSVCRT.LIB, but it's a "gateway" (I don't know what is the technical word for it) to code contained in MSVCRT.DLL (This code include string and wstring templates instantation). Perhaps you found more help in MSDN Knoledgement Base: Q168958 "HOWTO: Exporting STL Components Inside & Outside of a Class" and Q172396 "PRB: Accedd Violation When Accesing STL Object in DLL". A question: Is the class interface imposed by Autocad? In your owned interfaces, you can try avoid the problematic class. In Autocad interfaces, you must try avoid copying strings. You can create a new string without references: aFunction(const string& str) { // create a NEW string and copy the string passed, // it didn't reference to string passed. string MyStr(str.c_str()); Quote: }
Luck! Gonzalo.
|
Mon, 19 Jan 2004 22:31:23 GMT |
|
 |
Araga #7 / 11
|
 Access Violation with map<string,xxx>
Hi Gonzalo, I have read microsot articles on the past and my code is compliant with it. The class interface is not imposed by Autocad. I just want clarify this point for 2 reasons: a)- My setAt funcion works with "(*m_pMapDictEntry)[tempKey.c_str()]= pDictEntry;",but dont work with "(*m_pMapDictEntry)[tempKey] = pDictEntry;". So I am not sure if I solved my problem with c_str() or just I am hidding my problem. b)- I Cant use my template class (template<typename KEY, class T>class CSgDictionaryImpl) because my CSgDictionaryImpl<KEY,T>::setAt is defined: template<typename KEY, class T> Sag::ErrorStatus CSgDictionaryImpl<KEY, T>::setAt(const KEY& key, T* pDictEntry) { (*m_pMapDictEntry)[tempKey] = pDictEntry; return Sag::eOk; Quote: }
So, to solve this problem, I had to create another template class (template<class T>class CSgDictionaryStringImpl) with just one difference : CSgDictionaryStringImpl<T>::setAt(const std::string& key, T* pDictEntry) { (*m_pMapDictEntry)[tempKey.c_str()] = pDictEntry; return Sag::eOk; Quote: }
But if the problem is string reference count, I dont mind to use this approach. One more time, Thanks for your support. Cheers, Aragao Quote: >Miltihreaded DLL link to MSVCRT.LIB, but it's a "gateway" (I don't know >what is the technical word for it) to code contained in MSVCRT.DLL (This >code include string and wstring templates instantation). >Perhaps you found more help in MSDN Knoledgement Base: Q168958 "HOWTO: >Exporting STL Components Inside & Outside of a Class" and Q172396 "PRB: >Accedd Violation When Accesing STL Object in DLL". >A question: Is the class interface imposed by Autocad? In your owned >interfaces, you can try avoid the problematic class. In Autocad >interfaces, you must try avoid copying strings. >You can create a new string without references: >aFunction(const string& str) >{ > // create a NEW string and copy the string passed, > // it didn't reference to string passed. > string MyStr(str.c_str()); >} >Luck! >Gonzalo. >.
|
Tue, 20 Jan 2004 00:46:53 GMT |
|
 |
Gonzalo Matama #8 / 11
|
 Access Violation with map<string,xxx>
Hi Aragao. Quote: > a)- My setAt funcion works with > "(*m_pMapDictEntry)[tempKey.c_str()]= pDictEntry;",but > dont work with "(*m_pMapDictEntry)[tempKey] = > pDictEntry;". So I am not sure if I solved my problem with > c_str() or just I am hidding my problem.
If you use c_str() you hide the problem, I'm afraid, because you use a pointer as key the, but not the array of char. The pointer can or can not reference to a valid array of char. Quote: > b)- I Cant use my template class (template<typename KEY, > class T>class CSgDictionaryImpl) because my > CSgDictionaryImpl<KEY,T>::setAt is defined: > template<typename KEY, class T> Sag::ErrorStatus > CSgDictionaryImpl<KEY, T>::setAt(const KEY& key, T* > pDictEntry) > { > (*m_pMapDictEntry)[tempKey] = pDictEntry; > return Sag::eOk; > } > So, to solve this problem, I had to create another > template class (template<class T>class > CSgDictionaryStringImpl) with just one difference : > CSgDictionaryStringImpl<T>::setAt(const std::string& key, > T* pDictEntry) > { > (*m_pMapDictEntry)[tempKey.c_str()] = pDictEntry; > return Sag::eOk; > }
I see. Is a ugly solution redefine setAt method. Perhaps you need create a new type wrapping string class. For example: class NewString { public: NewString(): m_str(0); NewString(const NewString& rhs) { if (strlen(rhs())) { m_str = new char [strlen(rhs()) + 1]; m_str[strlen(rhs())] = '\0'; } } NewString(const string& str) { m_str = new char[str.length() + 1]; m_str[str.length()] = '\0'; } ~NewString() { if (m_str) delete[] m_str; } bool operator <(const NewString& rhs) const { return strcmp(m_str, rhs()) < 0; } const char * operator ()() const { return m_str; } Quote: }
And then you can use CSgDictionaryImpl<NewString, T>. Now, you can do: string a("Peter); dict.setAt(a, something); because there is a constructor from string to NewString. But the New string is not transparent, I'm affraid. You need use: NewString b; string a(b()); // or string a = b(); It's an idea. Gonzalo.
|
Tue, 20 Jan 2004 16:37:59 GMT |
|
 |
Araga #9 / 11
|
 Access Violation with map<string,xxx>
Hi Gonzalo, I didnt understand when you said that I use a pointer as key. My Dictionaries implementation (CSgDictionaryImpl and CSgStringDictionaryImpl) encapsulate the class std::map. Your member variables is std::map<KEY, T* >* m_pMapDictEntry and std::map<std::string, T* >* m_pMapDictEntry; So, when I instantiate my CSgDictionaryImpl with std::string and CSgObject I have a member variable std::map<std::string, CSgObject*> I know that is ugly the solution with CSgDictionaryStringImpl. But, Do you think that I will have problem using c_str()? Your string class is a good idea. But I would like to use stl library yet. On my implementation, I use a lot of std::string member functions. Maybe another solution is have a new string class derived from std::string and implement de copy constructor and operator= to alocate another space memory, how do you did on your implementation class string. But if with c_str() I will not have problem, I prefer use it. Cheers, Aragao Quote: >-----Original Message-----
>Hi Aragao. >> a)- My setAt funcion works with >> "(*m_pMapDictEntry)[tempKey.c_str()]= pDictEntry;",but >> dont work with "(*m_pMapDictEntry)[tempKey] = >> pDictEntry;". So I am not sure if I solved my problem with >> c_str() or just I am hidding my problem. >If you use c_str() you hide the problem, I'm afraid, because you use a >pointer as key the, but not the array of char. The pointer can or can >not reference to a valid array of char. >> b)- I Cant use my template class (template<typename KEY, >> class T>class CSgDictionaryImpl) because my >> CSgDictionaryImpl<KEY,T>::setAt is defined: >> template<typename KEY, class T> Sag::ErrorStatus >> CSgDictionaryImpl<KEY, T>::setAt(const KEY& key, T* >> pDictEntry) >> { >> (*m_pMapDictEntry)[tempKey] = pDictEntry; >> return Sag::eOk; >> } >> So, to solve this problem, I had to create another >> template class (template<class T>class >> CSgDictionaryStringImpl) with just one difference : >> CSgDictionaryStringImpl<T>::setAt(const std::string& key, >> T* pDictEntry) >> { >> (*m_pMapDictEntry)[tempKey.c_str()] = pDictEntry; >> return Sag::eOk; >> } >I see. Is a ugly solution redefine setAt method. Perhaps you need create >a new type wrapping string class. For example: >class NewString >{ >public: > NewString(): m_str(0); > NewString(const NewString& rhs) > { > if (strlen(rhs())) > { > m_str = new char [strlen(rhs()) + 1]; > m_str[strlen(rhs())] = '\0'; > } > } > NewString(const string& str) > { > m_str = new char[str.length() + 1]; > m_str[str.length()] = '\0'; > } > ~NewString() > { > if (m_str) delete[] m_str; > } > bool operator <(const NewString& rhs) const > { > return strcmp(m_str, rhs()) < 0; > } > const char * operator ()() const > { > return m_str; > } >} >And then you can use CSgDictionaryImpl<NewString, T>. >Now, you can do: >string a("Peter); >dict.setAt(a, something); >because there is a constructor from string to NewString. >But the New string is not transparent, I'm affraid. You need use: >NewString b; >string a(b()); // or string a = b(); >It's an idea. >Gonzalo. >.
|
Tue, 20 Jan 2004 19:40:03 GMT |
|
 |
Gonzalo Matama #10 / 11
|
 Access Violation with map<string,xxx>
Hi Aragao.
<snip> Quote: > I know that is ugly the solution with > CSgDictionaryStringImpl. But, Do you think that I will > have problem using c_str()?
<snip> I don't know you'll have problem using c_str() but I think you'll can have it. c_str() return a const char *, a pointer to array of char. This pointer is valid while the array is allocated in memory, and the array is in memory while there are any string reference. For example: void a_function(T *p) { string str("some key"); dict->setAt(str, p); Quote: }
void another_function() { string str("some key"); T *p = dict->getAt(str); Quote: }
In this example, the strings used as key are defined locally. In a_function(), Dictionary class use str.c_str() as map key. c_str() is a pointer to memory allocated by str defined in a_function(). Exiting of function, str destructor is invoked and, in this case (only string reference it), memory is deallocated, and map has a pointer to deallocated memory as key. In another_function(), then new string allocate memory for "some key", and that memory can not match with key pointer in map, and you'll not get the dictionary entry. If str is a global variable, and the string you pass to both CsgDictionaryStringImpl methods reference to the same memory (string is reference count), you'll not any problem. I think if you redefine setAt() and getAt() for use c_str(), is better redefine so: CSgDictionaryStringImpl< T >::setAt( const std::string& key, T* pDictEntry) { // Create a new string but don't invoke copy constructor string newKey(key.c_str(), key.length()); // The new string is the key (*m_pMapDictEntry)[newKey] = pDictEntry; return Sag::eOk; Quote: }
T* CsgDictionaryStringImpl<T>::getAt( const std::string& key) const { string newKey(key.c_str(), key.length()); ... Quote: }
Now: - you use STL string in interface and in implementation, - is safe with independece of the class client code, - it has not problem with DLLs heaps. What do you think of this? Gonzalo.
|
Tue, 20 Jan 2004 20:14:53 GMT |
|
 |
Gonzalol Matama #11 / 11
|
 Access Violation with map<string,xxx>
Hi Aragao. I think I didn't understand you when you proposed using c_str(). If you use map<std::string, CsgObject *> and insert elements: (*m_pMapDicEntry)[str.c_str()]; the implicit string(const char *) implicit constructor is called and copy without count reference is done. It's all right. I'm sorry. Greetings. Gonzalo.
|
Fri, 23 Jan 2004 15:49:02 GMT |
|
|
|