Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >How to make a c++11 std::unordered_set of std::weak_ptr

How to make a c++11 std::unordered_set of std::weak_ptr
EN

Stack Overflow用户
提问于 2012-12-04 03:30:42
回答 4查看 8.5K关注 0票数 15

我有一个这样的集合:set<weak_ptr<Node>, owner_less<weak_ptr<Node> > > setName;

它工作得很好。但是我想把它改成一个无序的集合。然而,当我这样做的时候,我得到了大约六页的错误。你知道怎么做吗?

在浏览了所有页面的错误消息后,我找到了可能有帮助的代码行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/usr/include/c++/4.7/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type
/usr/include/c++/4.7/bits/stl_function.h: In instantiation of ‘bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = std::weak_ptr<Node>]:
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-12-04 15:30:16

请阅读下面的 答案,因为我的答案是不正确的,尽管我是公认的解决方案。

由于unordered_sets是基于散列的,因此必须为std::weak_ptr数据类型提供散列function object

如果您查看unordered_set模板参数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<class Key,
    class Hash = std::hash<Key>,
    class Pred = std::equal_to<Key>,
    class Alloc = std::allocator<Key> >
    class unordered_set;

您会注意到,std::unordered_set为您提供了一个默认的std::hash<>模板参数。但是,由于std::hash只为数据类型的specific set提供专门化,您可能需要提供自己的专门化。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<typename T>
struct MyWeakPtrHash : public std::unary_function<std::weak_ptr<T>, size_t> {
   size_t operator()(const std::weak_ptr<T>& wp)
   {
      // Example hash. Beware: As zneak remarked in the comments* to this post,
      // it is very possible that this may lead to undefined behaviour
      // since the hash of a key is assumed to be constant, but will change
      // when the weak_ptr expires
      auto sp = wp.lock();
      return std::hash<decltype(sp)>()(sp);
   }
};

编辑:您还需要提供一个相等函数,因为没有提供weak_ptr的std::equal_to。在"Equality-compare std::weak_ptr" on Stackoverflow中采用一种可能的方法来完成此操作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<typename T>
struct MyWeakPtrEqual : public std::unary_function<std::weak_ptr<T>, bool> {

   bool operator()(const std::weak_ptr<T>& left, const std::weak_ptr<T>& right)
   {
      return !left.owner_before(right) && !right.owner_before(left);
   }
};

所有这些结合在一起,给我们提供了以下内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::unordered_set<std::weak_ptr<T>,
                   MyWeakPtrHash<T>,
                   MyWeakPtrEqual<T>> wpSet;
票数 1
EN

Stack Overflow用户

发布于 2015-06-18 17:49:25

简短而不幸的答案是,虽然shared_ptr<>可以安全地用作无序集合或映射中的键,但weak_ptr<>不能也不能。再多的花招也不能保证它的安全。

这是因为weak_ptr的接口不公开对共享控制对象的访问,这是在有序集或映射中使用时按owner_before()进行比较的基础。

虽然锁定指针然后散列shared_ptr似乎是合理的,但事实并非如此。如果最后一个shared_ptr超出作用域,则哈希值将更改,这将导致下次迭代您的集或映射时出现未定义的行为。这很可能不会被注意到,直到你的代码在客户面前生产,你偶尔会遇到意想不到的和莫名其妙的功能损失,但你的单元测试仍然会毫无瑕疵地通过,给你一个错误的想法,你的测试覆盖率很好,你的代码是可靠的,应该归咎于用户、硬件或网络。

因此,总而言之,如果您打算使用weak_ptr来构建您的无主对象缓存(它们非常适合),那么您需要使用std::set<weak_ptr>并遭受极小的性能影响(尽管在现实中,这与保护set的mutex所造成的性能损失相比会相形见绌)。

如果你真的想使用一个weak_ptr作为一个无序键,你必须自己编写(提示:使用共享控制块的地址作为散列函数的基础)。

票数 24
EN

Stack Overflow用户

发布于 2014-03-01 05:48:07

我不认为建议的散列函数是正确的。如果指向该对象的所有共享指针都消失了,则weak_ptr<X>::lock()将返回空的shared_ptr,其散列值可能为零。因此哈希函数可以在一段时间内返回不同的值。

我认为正确的解决方案是使用boost::unordered_map<X*, boost::weak_ptr<X>>。类型X*可以很容易地用作散列映射的关键字,而weak_ptr<X>作为值让您有机会了解被引用的对象是否仍然存在。

要将值存储到此哈希中,您可以使用以下内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (boost::shared_ptr<X> p = wp.lock()) {
    // weak_ptr is still valid
    ptrs.insert(std::make_pair(p.get(), p));
}
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13695640

复制
相关文章
C++11异步编程(std::async, std::future, std::packaged_task, std::promise)
       std::async是一个函数模板,会启动一个异步任务,最终返回一个std::future对象。在之前我们都是通过thread去创建一个子线程,但是如果我们要得到这个子线程所返回的结果,那么可能就需要用全局变量或者引用的方法来得到结果,这样或多或少都会不太方便,那么async这个函数就可以将得到的结果保存在future中,然后通过future来获取想要得到的结果。async比起thread来说可以对线程的创建又有了更好的控制,比如可以延迟创建。下面先介绍一下std::future, std::packaged_task, std::promise。
Ch_Zaqdt
2020/02/15
16.1K0
C++11 std::async
//g++ -std=c++11 -pthread -g std_future.cpp -o main // async example #include <iostream> // std::cout #include <future> // std::async, std::future // a non-optimized way of checking for prime numbers: bool is_prime (long int x) { std::co
awk
2018/08/23
4680
C++11 std::bind std::function 高级使用方法[通俗易懂]
Hello world ! sumFunc.Call<int>(1, 2, 3) : 6
全栈程序员站长
2022/02/04
9970
c++11:std::copy示例
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/84709909
10km
2019/05/25
1.7K0
std::function与std::bind
一、背景介绍: 函数指针始终不太灵活,它只能指向全局或静态函数,对于类成员函数、lambda表达式或其他可调用对象就无能为力了,因此,C++11推出了std::function与std::bind这两件大杀器,他们配合起来能够很好的替代函数指针。
灰子学技术
2022/01/18
9360
C++11:基于std::queue和std::mutex构建一个线程安全的队列
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/52067929
10km
2019/05/25
10.7K0
cmake+gcc解决extended initializer lists only available with -std=c++11 or -std=gnu++11
有时,我们需要一个结构体变量做为参数传递给函数,后面又不需要再用到这个结构体变量,所以如果专门定义一个变量,再将这个变量传递给函数就显得挺罗嗦。 就像下面这段代码,tmpStruct只是起到一个数据包装的作用,调用test()之后并不再用到,所以这个变量就显示有些多余 。
10km
2022/05/07
6350
理解std::move和std::forward
std::move和std::forward只是执行转换的函数(确切的说应该是函数模板)。std::move无条件的将它的参数转换成一个右值,而std::forward当特定的条件满足时,才会执行它的转换。这就是它们本来的样子.这样的解释产生了一些新问题,但是,基本上就是这么一回事。
杨永贞
2022/06/08
1.8K0
理解std::move和std::forward
std::jthread与std::thread区别
​std::jthread是C++20新引入的线程类,与 std::thread 类似,或者说,jthread是对thread进一步的封装,功能更强大​。
音视频牛哥
2022/04/03
1.3K0
std::atomic和std::mutex区别
​模板类std::atomic是C++11提供的原子操作类型,头文件 #include<atomic>。​在多线程调用下,利用std::atomic可实现数据结构的无锁设计。​​
音视频牛哥
2022/03/12
2.9K0
std::atomic和std::mutex区别
C++11 std::lock_guard 互斥锁
C++11中加入了线程,引入了多线程,也就伴随着一个多线程资源互斥的操作。对于锁的使用,有一个比较头疼的问题,就是在加锁后,容易忘记解锁,这样程序中可能会造成死锁。C++11中加入了lock_guard,这个的使用,可以让你不用关注解锁!
fensnote
2021/05/31
1.7K0
c++11:如何判断std::function对象相同?
我们知道std::function的实质就是个函数指针,但在c++11中std::function并没有实现操作符==(要到C++20才实现),所以我们无法使用==操作符来判断两个std::function对象是否相等,虽然我们明明知道它就是个指针。
10km
2020/04/08
1.8K0
<c++ 常用代码块> | std::string 与 std::wstring转化
#include <string>#include <locale>#include <codecvt>// convert string to wstringinline std::wstring to_wide_string(const std::string& input){std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;return converter.from_bytes(input);}// convert wstring t
IsEva
2022/12/05
9890
c++中的std::stod, stCPP程序说明std::stod():stof, std::stold
如果未执行转换,则会引发invalid_argument异常。如果读取的值超出双精度的可表示值范围,则会引发out_of_range异常。无效的 idx 会导致未定义的行为。
鲸落c
2022/12/14
3K0
想看懂WebRtc,你须知道的C++11新特性「lambda,std::function以及std:bind」
在本文中,我们来聊一下lambda表达式,闭包,std::function以及std::bind。
音视频_李超
2020/04/02
8430
std::function与std::bind使用总结
C++中函数指针的用途非常广泛,例如回调函数,接口类的设计等,但函数指针始终不太灵活,它只能指向全局或静态函数,对于类成员函数、lambda表达式或其他可调用对象就无能为力了,因此,C++11推出了std::function与std::bind这两件大杀器。
forrestlin
2019/07/29
11.4K0
诡异!std::bind in std::bind 编译失败
当时看了报错,简单的以为跟之前遇到的原因一样,随即提出了解决方案,怎奈,短短几分钟,就被无情打脸,啪啪啪😭。为了我那仅存的一点点自尊,赶紧看下原因,顺便把之前的问题也回顾下。
高性能架构探索
2023/06/13
7880
诡异!std::bind in std::bind 编译失败
C++11特性之std:call_once介绍
std:call_once是C++11引入的新特性,如需使用,只需要#include <mutex>即可,简单来说std:call_once的作用,确保函数或代码片段在多线程环境下,只需要执行一次,常用的场景如Init()操作或一些系统参数的获取等。
音视频牛哥
2022/05/12
2.3K0
C++11特性之std:call_once介绍
[C++11札记]: std::function
在C/C++中函数指针作为一种回调机制被广泛使用,但是函数指针在C++面向对象编程中有些不足,比如无法捕捉上下文。举个例子,使用对象的非静态成员函数作为函数指针就无法做到。
acoolgiser
2019/06/14
2.2K0
[C++11札记]: std::bind
在上一篇文章中,我们提到可调用对象(callable object),其中一种就是std::bind表达式。在这篇文章中,我们来谈谈std::bind表达式。
云水木石
2019/07/02
1.5K0

相似问题

带有std::weak_ptr的std::make_shared分配

28

std::make_shared()、std::weak_ptr和循环引用

37

std::std::weak_ptr向量和std::查找

11

std:bind和std::weak_ptr

13

成员函数中与本地静态std::map<std::string、std::weak_ptr>的访问冲突(C++11/STL)

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文