【发布时间】:2016-12-14 12:10:41
【问题描述】:
std::shared_ptr::unique() 的技术问题是什么,导致它在 C++17 中被弃用?
根据cppreference.com,std::shared_ptr::unique() 在 C++17 中被弃用为
从 C++17 开始不推荐使用此函数,因为
use_count只是多线程环境中的近似值。
我理解这对于use_count() > 1 是正确的:当我持有对它的引用时,其他人可能同时放开他的或创建一个新副本。
但是如果 use_count() 返回 1(这是我在调用 unique() 时感兴趣的内容),那么没有其他线程可以以一种活泼的方式更改该值,所以我希望这应该是安全的:
if (myPtr && myPtr.unique()) {
//Modify *myPtr
}
我自己搜索的结果:
我找到了这个文档:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0521r0.html,它提议弃用以响应 C++17 CD 评论 CA 14,但我找不到该评论本身。
作为替代方案,该论文建议添加一些注释,包括以下内容:
注意:当多个线程可以影响
use_count()的返回值时,应将结果视为近似值。 特别是,use_count() == 1并不意味着通过先前销毁的shared_ptr的访问在任何意义上都已完成。 — 结束说明
我知道当前指定 use_count() 的方式可能就是这种情况(由于缺乏保证同步),但为什么解决方案不只是指定此类同步并因此使上述模式安全?如果存在不允许此类同步的基本限制(或使其代价高昂),那么如何正确实现析构函数?
更新:
我忽略了@alexeykuzmin0 和@rubenvb 提出的明显案例,因为到目前为止,我只在其他线程本身无法访问的shared_ptr 实例上使用了unique()。因此,该特定实例不会以不正当的方式被复制。
我仍然有兴趣了解 CA 14 到底是什么,因为我相信我的所有 unique() 用例只要保证与其他 shared_ptr 不同实例发生的任何情况同步就可以工作线程。所以它对我来说似乎仍然是一个有用的工具,但我可能会在这里忽略一些基本的东西。
为了说明我的想法,请考虑以下内容:
class MemoryCache {
public:
MemoryCache(size_t size)
: _cache(size)
{
for (auto& ptr : _cache) {
ptr = std::make_shared<std::array<uint8_t, 256>>();
}
}
// the returned chunk of memory might be passed to a different thread(s),
// but the function is never accessed from two threads at the same time
std::shared_ptr<std::array<uint8_t,256>> getChunk()
{
auto it = std::find_if(_cache.begin(), _cache.end(), [](auto& ptr) { return ptr.unique(); });
if (it != _cache.end()) {
//memory is no longer used by previous user, so it can be given to someone else
return *it;
} else {
return{};
}
}
private:
std::vector<std::shared_ptr<std::array<uint8_t, 256>>> _cache;
};
这有什么问题吗(如果unique()实际上会与其他副本的析构函数同步)?
【问题讨论】:
-
为什么 1 是特例?在您致电
unique之后以及在您完成您正在做的任何事情之前,可能会创建另一个副本。 -
@rubenvb:我的错误 - 唯一的是 const,所以另一个线程可以在没有数据竞争的情况下进行复制
-
const与此无关。如果持有 shared_ptr 的对象本身可以从多个线程访问,则无论如何都可以制作 shared_ptr 的副本。 -
@MikeMB,我正要回答你的更新,但我看到 alexeykuzmin0 的回答中的一句话几乎回答了你的更新。你是对的,如果你的每个线程只使用 shared_ptr 的副本,那么 unique() 就可以正常工作。在您引用的论文和 alexykuzmin0 的答案中,多个线程共享对唯一 shared_ptr 的引用...在 alexykuzmin0 的答案中,句子“
unique()=true表示没有人有指向同一内存的 shared_ptr...可能会说几乎一样的话不? -
当然
use_count没有被弃用,所以你可以继续使用use_count()==1,只要你记得它是活泼的。
标签: c++ multithreading shared-ptr c++17