Jump to content
  • Advertisement
Sign in to follow this  
Sepiantum

Explicit instantiations needed for unordered_map

This topic is 2494 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
Advertisement
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...

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
Would declaring CConsole as a pure virtual interface and providing a method CreateConsole() that instantiates a console class derived from CConsole work?

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!