我有一个包含类的共享库:
// 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);
}
现在我想在非共享库(简单控制台应用程序)中使用此类:
WorldSettings::Get<int>("WorldMinutes");
'WorldMinutes'在共享库代码中设置:
WorldSettings::Set<int>("WorldMinutes", 0);
问题是:
浮点异常
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; }
回溯:
#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)
在共享库代码中Set<int>(...)
时调用错误。有趣的是,从库代码调用Get
时我没有错误。这可能有什么问题?
答案 0 :(得分:3)
代码不正确。
您在.cpp文件中定义的特殊化应该已经在.hpp文件中声明(在类之外),否则每次尝试使用定义的函数时都会有未定义的行为。
添加:
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);
在课程定义之后。
这告诉编译器定义是在别处生成的。
实际上,共享库很可能会生成自己的函数副本(你提供了一些默认的模板实现吗?),这可能会造成严重破坏。
这可能不是导致错误的原因,但进一步调查是没有意义的。
答案 1 :(得分:2)
这不是一个答案,而是强烈推荐的改进建议:摆脱这些宏,并使用C ++模板:
template <typename Map>
typename Map::mapped_type const & cget(Map const & m, typename Map::key_type const & k)
{
typename Map::const_iterator it = m.find(k);
assert(it != m.cend());
return it->second;
}
template <typename Map>
typename Map::mapped_type & get(Map & m, typename Map::key_type const & k)
{
typename Map::iterator it = m.find(k);
assert(it != m.end());
return it->second;
}
template <typename Map>
typename Map::mapped_type & put(Map & m, typename Map::key_type const & k, typename Map::mapped_type const & v)
{
std::pair<typename Map::iterator, bool> p = m.insert(typename Map::value_type(k, v));
return p.first->second;
}
现在你可以说:
template <>
int & WorldSettings::Get<int>(const std::string & key)
{
get(mIntegerStorage, key);
}
template <>
float & WorldSettings::Set<float>(const std::string & key, float value)
{
put(mFloatStorage, key, value);
}
您甚至可以将专业化移动到容器:getter / setter通常会变为:
template <typename T> static T & Get(const std::string & key)
{
return get(Storage<T>::container, key);
}
template <typename T> static T & Set(const std::string & key, T value)
{
return put(Storage<T>::container, key, value);
}
您只需要一个嵌套类:
template <typename T> struct Storage
{
static std::unordered_map<std::string, T> container;
};
现在您只需要为要使用的容器提供具体的对象实例:
template <>
std::unordered_map<std::string, int> WorldSettings::Storage<int>::container{};
答案 2 :(得分:0)
我的猜测是,您要在构造静态成员之前尝试访问它们,即Static Initialization Order Fiasco。
如果尚未构造全局变量,则在尝试使用它们时会出现不确定的行为。