I have a shared library with class:
// HPP:
class WorldSettings
{
private:
static std::unordered_map<std::string, int> mIntegerStorage;
static std::unordered_map<std::string, float> mFloatStorage;
static std::unordered_map<std::string, std::string> mStringStorage;
public:
template <typename T>
static T &Get(const std::string &key);
template <typename T>
static T &Set(const std::string &key, T value);
};
// CPP:
#define DoReturn(MapName, Key, Type) { \
assert( MapName.find(Key) != MapName.end() && "No such key in world settings!" ); \
return MapName[Key]; \
} \
#define DoSetup(MapName, Key, Value) { \
MapName[key] = Value; \
return MapName[Key]; \
} \
std::unordered_map<std::string, int> WorldSettings::mIntegerStorage;
std::unordered_map<std::string, float> WorldSettings::mFloatStorage;
std::unordered_map<std::string, std::string> WorldSettings::mStringStorage;
// Getters
template <>
int &WorldSettings::Get<int>(const std::string &key)
{
DoReturn(mIntegerStorage, key, int);
}
template <>
float &WorldSettings::Get<float>(const std::string &key)
{
DoReturn(mFloatStorage, key, float);
}
template <>
std::string &WorldSettings::Get<std::string>(const std::string &key)
{
DoReturn(mStringStorage, key, std::string);
}
// Setters
template <>
int &WorldSettings::Set<int>(const std::string &key, int value)
{
DoSetup(mIntegerStorage, key, value);
}
template <>
float &WorldSettings::Set<float>(const std::string &key, float value)
{
DoSetup(mFloatStorage, key, value);
}
template <>
std::string &WorldSettings::Set<std::string>(const std::string &key, std::string value)
{
DoSetup(mStringStorage, key, value);
}
Now I want to use this class in non shared library (simple console application):
WorldSettings::Get<int>("WorldMinutes");
The 'WorldMinutes' is set in shared library code:
WorldSettings::Set<int>("WorldMinutes", 0);
The problem is:
Floating point exception
Program received signal SIGFPE, Arithmetic exception.
0x00000000004d1f61 in std::__detail::_Mod_range_hashing::operator() (this=0x747863, __num=732984944481197501,
__den=0) at /usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.2/../../../../include/c++/4.6.2/bits/hashtable_policy.h:376
376 { return __num % __den; }
Backtrace:
#0 0x00000000004d1f61 in std::__detail::_Mod_range_hashing::operator() (this=0x747863, __num=732984944481197501,
__den=0) at /usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.2/../../../../include/c++/4.6.2/bits/hashtable_policy.h:376
#1 0x00000000004d3503 in std::__detail::_Hash_code_base<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::equal_to<std::string>, std::hash<std::string>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_bucket_index (this=0x747860, __c=732984944481197501, __n=0)
at /usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.2/../../../../include/c++/4.6.2/bits/hashtable_policy.h:758
#2 0x00000000004d2a9a in std::__detail::_Map_base<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, true, std::_Hashtable<std::string, std::pair<std::string const, int>, std::allocator<std::pair<std::string const, int> >, std::_Select1st<std::pair<std::string const, int> >, std::equal_to<std::string>, std::hash<std::string>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true> >::operator[] (this=0x747860, __k=...)
at /usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.2/../../../../include/c++/4.6.2/bits/hashtable_policy.h:543
#3 0x00000000004d1cfa in WorldSettings::Set<int> (key=..., value=0)
The error is called when Set<int>(...) in shared library code. The interesting thing is that I don't have an error when call Get from library code. What could be wrong here?
The code is incorrect as it is.
The specializations you define in the .cpp file should have been declared (out of the class) in the .hpp file, otherwise any time you try to use the defined function you have undefined behavior.
Add:
template <>
int &WorldSettings::Get<int>(const std::string &key);
template <>
float &WorldSettings::Get<float>(const std::string &key);
template <>
std::string &WorldSettings::Get<std::string>(const std::string &key);
// Setters
template <>
int &WorldSettings::Set<int>(const std::string &key, int value);
template <>
float &WorldSettings::Set<float>(const std::string &key, float value);
template <>
std::string &WorldSettings::Set<std::string>(const std::string &key, std::string value);
right after the class definition.
This tells the compiler that the definitions are generated elsewhere.
As it is, it is likely that the shared library will generate its own copy of the functions (did you provided some default template implementation ?) and that may cause havoc.
It may not be the cause of the bug, but it does not make sense to investigate further.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With