学习笔记——c++自定义class用于unordered

来源:互联网 发布:数据库服务器 编辑:程序博客网 时间:2024/05/23 10:26
unordered


unordered_set和unordered_map基本接口与set和map类似,区别在于其内部构造并不是红黑树而是散列表,通常来说散列表的效率更高。

需要注意的是unordered可以应用于内置类型,但用户自定义的class必须定义operator==和hash函数才能装入容器。

有如下class

class A{private:    size_t _x;public:    friend bool operator==(const A& lh, const A& rh)    {        return (lh.getX() == rh.getX());      };       A(size_t x = 0) :_x(x) { std::cout << "A::A()" << std::endl; };       int getX() const{return _x;};  };



为了使用unordered_set<A> ,有四种方法定义hash函数,传入容器

(1) 使用普通函数,利用function
size_t hash_value(const A &a){    return std::hash<int>()(a.getX());}int main(){    unordered_set<A, function<size_t(const A &a)> >  s(1, hash_value);    //function写起来比较麻烦,也可以直接用decltype推导类型    unordered_set<A, decltype(&hash_value)>  s(1, hash_value);    A a(0);    s.insert(a);    return 0;}

   这种实现方便简单,但是必须用带参数的unordered_set constructor


(2)使用lambda
int main(){    unordered_set<A, function<size_t(const A &a)>>    s(1, [](const A &a)        {        return std::hash<int>()(a.getX());        }  );    A a(0);    s.insert(a);    return 0;}
    lambda可以直接在constructor中定义匿名函数,但这种写法比较不易读,而且不能使用decltype,必须由程序员指定类型。

(3) 使用function object

struct hash_value{    size_t operator()(const A &a) const    {        return std::hash<int>()(a.getX());    }};int main(){    unordered_set<A, hash_value> s;    A a(0);    s.insert(a);    return 0;}

(4) Specializing std::hash

    如果我们需要定义一个class供其他人使用,为了能够应用于unordered容器必须拥有一个hash函数,而让客户定义hash函数是不合适的。对于这种问题,一个较好的解决方法是模板特化

namespace std{    template<>    class hash<A>    {    public:        size_t operator()(const A &a) const        {            return std::hash<int>()(a.getX());        }    };};int main(){    unordered_set<A> s    A a(0);    s.insert(a);    return 0;}
这种方法可以使自定义的class像内置类型一样使用,但需要注意如果特化的模板可能会污染匿名空间,对其他不相关的class造成意料之外的影响。


参考资料:

http://marknelson.us/2011/09/03/hash-functions-for-c-unordered-containers/

《Boost程序库完全开发指南》 P267

0 0
原创粉丝点击