调用“unordered_set <vector<int>>”的隐式删除默认构造函数

31

尝试定义一个vector的unordered_set时会出现错误,错误提示为:“调用了unordered_set< vector<int> >的已删除默认构造函数”。但是,如果定义一个常规的(有序的)set:set< vector<int> >则不会出现这种情况。看起来我需要定义一个hash<vector<int>>才能摆脱这个错误。

有人知道为什么只有在使用unordered_set时才会出现此错误吗?两种数据结构都应该使用哈希,那么为什么unordered_set需要自定义哈希函数?实际上,一个常规的(有序的)set是否也需要一些自定义比较器以便对vector<int>数据结构进行排序?


3
std::vector 已经重载了 < 运算符。这就是为什么它可以与 std::set 一起使用的原因。 - PaulMcKenzie
8
std::set 不使用哈希。 - Mankarse
建议使用unordered_set<T*>而不是unordered_set<T>,因为mysql-server和rocksdb都广泛使用了它。 - Lewis Chan
5个回答

15

这是因为unordered_set使用std::hash模板来计算其条目的哈希值,而对于pair类型没有std::hash。您需要定义自定义哈希函数才能使用unordered_set。

    struct vector_hash
{
    template <class T1, class T2>
    std::size_t operator () (std::pair<T1, T2> const &v) const
    {
        return std::hash<T1>()(v.size());    
    }
};

然后将您的unordered_set声明为 -

std::unordered_set< vector<int>, vector_hash> set;

这个哈希函数不太好,它只是一个例子。


11
一个存储了 vector<int>unordered_set 为什么需要对 pair 使用哈希函数?难道它不应该需要对 vector<int> 使用哈希函数吗? - Dominick Pastore
2
如果你正在寻找一个适用于pair<int,int>的好哈希函数,可以参考https://dev59.com/FHRB5IYBdhLWcg3wQFLu#682617。 - Anuraag Barde
我没有看到有这样的成员函数std::pair::size()。这个怎么编译的?https://en.cppreference.com/w/cpp/utility/pair - undefined

6

两种数据结构都应该使用哈希吗?

不需要。这已经有记录了,你可以自己查阅:

  • std::set

    std::set是一个关联容器,它包含一组类型为Key的唯一对象,并按照键值比较函数Compare进行排序。搜索、删除和插入操作具有对数复杂度。通常将集合实现为红黑树。

    请注意,默认情况下Compare使用std::less<Key>,而std::vector重载了operator<

  • std::unordered_set,供比较之用

    无序集合是一个关联容器,它包含一组类型为Key的唯一对象。搜索、插入和删除平均时间复杂度为常数。

    内部元素没有按任何特定顺序排序,而是组织成桶。元素放置在哪个桶中完全取决于其值的哈希值

    和哈希类型参数默认为std::hash<Key>。这里列出了标准库类型的专业化列表,但不包括std::vector


1

很遗憾,没有针对std::vector的通用std::hash专业化。只有一个std::vector<bool>的专业化,但它并不是很有帮助:

int main()
{
    std::hash<std::vector<bool>> hash_bool;  // ok
    std::hash<std::vector<int>> hash_int;  // error
}

演示

我认为原因是没有标准的方法来合并哈希值。因为你必须合并所有元素的哈希值才能构建整个向量的哈希值。但为什么没有标准的方法来合并哈希值 - 这是一个谜。

你可以使用boost::hashabsl::Hash,例如:

unordered_set<vector<int>, boost::hash<vector<int>>>

请注意,absl::Hash 计算的哈希码不能保证在程序的不同运行中稳定。这可能是一个优点(如果您追求安全性),也可能是一个缺点(如果您追求可重复性)。


0

我的回答与std::vector问题无关,但在我的情况下,我在std::string上遇到了“调用隐式删除的默认构造函数”错误,只是因为我没有包含<string>头文件。

我的意思是当在前向声明类型上使用unordered_map时,可能会发生该错误:

#include <unordered_map>
#include <string_view>
//#include <string>

int main()
{
    auto m = std::unordered_map<std::string, int>{};
}

-7

set使用自平衡树,而unordered_set使用纯哈希。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接