Explicit instantiations needed for unordered_map

Started by
8 comments, last by Sepiantum 12 years, 2 months ago
I've been trying to write a cvar system to export in a dll lately, and Microsoft's compiler is getting mad at me for not providing explicit instantiations for std::tr1::unordered_map<std::string, CCFunc*>. I've been trying to provide all sorts of explicit instantiantions, but I just end up with even more warnings.
Follow and support my game engine (still in very basic development)? Link
Advertisement
You're getting warnings or errors?
What does the warning say?
Warning used to look like this (I just suppressed it):
1>c:\important stuff\quantum game engine\quantum game engine\cvar\CConsole.h(28): warning C4251: 'CConsole::CFuncList' : class 'std::tr1::unordered_map<_Kty,_Ty>' needs to have dll-interface to be used by clients of class 'CConsole'
1> with
1> [
1> _Kty=std::string,
1> _Ty=CCFunc *
1> ]


Instead, I'm getting massive access violation errors when I run my code.

CConsole destructor:
//Destructor - clear the map
CConsole::~CConsole(){
//Loop through and delete what needs to be deleted
for(std::tr1::unordered_map<std::string, CCFunc*>::iterator it = this->CFuncList.begin(); it != this->CFuncList.end(); it++){
if(it->second->needs_delete){
delete it->second;
}
}
}


Remove code:
std::string CConsole::Remove(std::string _name){
if(this->CFuncList.count(_name)){
this->CFuncList[_name]->pConsole = nullptr;
//Use delete if needed
if(this->CFuncList[_name]->needs_delete){
delete this->CFuncList[_name];
}
this->CFuncList.erase(_name);
return _name + " was successfully removed from the function list";
} else {
return "Error: " + _name + " does not exist";
}
}


CCFunc destructor:
CCFunc::~CCFunc(){
//If not yet removed
if(this->pConsole){
this->pConsole->Remove(this->name);
}
this->name.clear();
this->desc.clear();
this->pConsole = nullptr;
}


When I run my app, it breaks with the error: Unhandled exception at 0x000007fef1e4b918 (cvar.dll) in cvar_test.exe: 0xC0000005: Access violation reading location 0xffffffffffffffff inside iosfwd (line 527) from this->desc.clear() inside the CCFunc destructor. Any ideas on what's going on?

EDIT: commenting out this->desc.clear() gives the same access violation in iosfwd (line 527) from this->pConsole = nullptr in the CCFunc destructor. I don't think a simple assignment should have this problem lol...
Follow and support my game engine (still in very basic development)? Link
That warning indicates that you are doing things wrong. You shouldn't be sharing template objects between DLLs/EXEs. Any subtle change, such as even a minor version difference between the compilers used to build them, or different compiler options, can and often will produce incompatible changes for template objects.

Between DLLs, it is safest to use C types and pure virtual classes. In the implementation you can use templates etc, you just cannot let them leak into the interface.

In any case it appears your code tries to destruct the object twice. Inside the CCFunc destructor, you call into the console, which will try to delete the CCFunc again. Perhaps assigning needs_delete = false might solve this, but overall I'm suspicious of the ownership semantics here.
Yeah I realized I was callling delete on CCFunc objects multiple times. Adding a needs_delete = false right before pConsole->Remove() fixes the problem.

So how would you suggest registering console variables and console functions with the console object?
Follow and support my game engine (still in very basic development)? Link
std::shared_ptr< > ftw ph34r.png
Would declaring CConsole as a pure virtual interface and providing a method CreateConsole() that instantiates a console class derived from CConsole work?
Follow and support my game engine (still in very basic development)? Link

Would declaring CConsole as a pure virtual interface and providing a method CreateConsole() that instantiates a console class derived from CConsole work?
[/quote]
It could, but said virtual interface must itself be written in terms of safe types. Remember even std::string is a template!

You also have to deal with DLLs having different heaps from executables, which means that memory allocated in a particular DLL must be deallocated in the same DLL.
According to this page, std::string is automatically exported by the C Runtime. So let me get this straight. CConsole should be declared like:


class __declspec(dllexport) CConsole {
public:
CConsole();
virtual ~CConsole();

virtual std::string Add(CCFunc* pFunc) = 0;
virtual std::string Remove(std::string name) = 0;

void delete_self(){ delete this; } //Implementation in another file of course
};


And then somewhere else, CConsole is implemented but not exported. Then, I define something like this:


CConsole* __declspec(dllexport) CreateConsole(){
return new CConsoleImplementation();
}


Or should I make everything char* instead? I'm pretty sure Microsoft is saying that using std::string as a return type is fine.
Follow and support my game engine (still in very basic development)? Link
I've uploaded what I've managed to put together so far. This version of the test still uses the exported unordered_map. I will change that code once somebody confirms my above post. Everything should be explained to you when you run the executable.

EDIT: help <command> is how you get help on a certain command. I forgot to include that in help.
Follow and support my game engine (still in very basic development)? Link

This topic is closed to new replies.

Advertisement