上下文:我有一个队列,支持来自两个不同(/或非)线程的单读/单写,为了强制执行此行为,即一次单读/单写,我需要限制拥有的线程数量队列一次为2(作者已经拥有该队列),我当时正在考虑为队列创建一个shared_ptr,并将编译时已知的最大引用计数设置为2。因此我的问题如下。
问题:有没有一种方法可以实现unique_pointer
具有编译时已知的最大引用计数的共享指针(可能使用 's)?我的情况是max_ref_count = 2
,超过引用计数限制 = 2 应该是编译时错误。
const auto p = std::make_shared<2, double>(2159); //works fine
const auto q = p; // works fine
const auto err1 = p; // does not compile
const auto err2 = q; // does not compile
编译时不可能
你所做的事情在编译时是不可能的,只能在运行时进行。请注意,它
std::shared_ptr
是可复制的,因此“复制路径可能会出现分歧”:此时,彼此之间
B
一无所知C
,也没有办法通过类型系统确保他们做到这一点。A
您最多可以计算从到以及后续副本的复制路径长度B
,但不能计算全局副本数量。这需要某种形式的有状态元编程,而 C++ 不支持这一点。
运行时困难
注意两个问题:
std::shared_ptr
预计还具有线程安全计数。这也意味着std::shared_ptr::use_count()
可能不会产生最新的结果,并且不能被视为可靠的指标。int
除了共享指针已有的原子计数器之外,您还需要分配一个新的计数器。这有点烦人,但可行。单线程解决方案
如果不考虑多线程的问题,可以直接使用
std::shared_ptr::use_count()
来跟踪使用情况。这是单线程程序中的可靠指标。您只需要创建一个包装器,std::shared_ptr
每当超出限制时就会抛出异常,这可能发生在复制构造函数和复制赋值运算符中。多线程解决方案
这有点复杂,我只提供大概的轮廓。
您可以
std::shared_ptr
使用自定义删除器创建一个。该自定义删除器可以包含一个std::atomic<std::size_t>
来可靠跟踪使用计数。有了这个,您不需要自己管理资源,而是可以让它做并随时
std::shared_ptr
访问删除器。base.get_deleter<counting_deleter>()
在复制构造函数中,与单线程解决方案类似,您将检查:
基本上,我们检查是否可以增加使用次数。如果不是,我们抛出,否则我们尝试增加
use_count
withcompare_exchange_weak
。复制赋值运算符是类似的。其他特殊成员函数可以默认,因为移动或破坏不能突破限制。
C++ 中的标准 std::shared_ptr 不直接提供在编译时设置最大引用计数的机制。但是,您可以通过创建具有有限引用计数的自定义智能指针来实现类似的行为。这是一个基本示例: