2011-11-27 40 views
3

我有一流的共享库:奇怪的无序地图的情况

// 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) 

错误时调用​​共享库的代码。有趣的是,我从库代码中调用Get时没有错误。这里有什么可能是错的?

+0

应该有更多的回溯 –

+0

那些通过使用迭代器,宏可以变得更加高效和常量正确。 –

+0

@ kerrek-sb我该怎么做? – Ockonal

回答

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); 

类定义之后。

这告诉编译器,定义是在别处生成的。

事实上,共享库很可能会生成它自己的函数副本(您是否提供了一些默认模板实现?),这可能会造成严重破坏。

这可能不是错误的原因,但进一步调查是没有意义的。

+0

听起来不错。 –

+1

这并没有帮助我:(仍然有同样的问题 – Ockonal

+0

@Ockonal:我无法重现该问题将getter和setter专业化的头,看看那会怎么样 –

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); 
} 

你可以甚至将专业化移动到容器:吸气剂/设定器一般变为:

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{}; 
+0

尼斯尖感谢 – Ockonal

+0

其实。!。你可以完全抛弃推杆,只是说'Storage :: container [key] = value;'并且用它来完成。同样的事情。 –