我正在使用unordered_set
将某些对象的所有权存储在unique_ptr
中。但是我不知道有什么好方法可以在时间到时从集合中删除其中一个。
代码看起来像这样:
typedef unique_ptr<MyType> MyPtr;
unordered_set<MyPtr> owner;
MyPtr p = make_unique<MyType>("foo")
MyType *pRaw = p.get();
owner.insert(std::move(p));
// Later ...
// I want to do something like this (cannot be written as-is, of course):
// owner.erase(pRaw);
有没有办法做到这一点?我当然可以用begin()
和end()
迭代整个集合,但是将它们放入集合中的全部目的是使这些查找有效。
我已经想到的一些事情:
shared_ptr
。对于我的情况,这是错误的抽象。所有权是唯一的。unique_ptr
提供的所有优点。unordered_set::begin(key)
查找存储桶。据我所知,我无法创建与要删除的unique_ptr
相匹配的密钥。但是很高兴被证明是错误的(:这是一个艰难的情况。 erase
有一个需要使用const key_type&
参数的重载,因此我们可以尝试创建一个“陈旧的” unique_ptr
以获取要删除的元素的哈希值:
template <typename T>
auto erase(std::unordered_set<std::unique_ptr<T>>& set, T* ptr)
{
std::unique_ptr<T> stale_ptr{ptr};
auto ret = set.erase(stale_ptr);
stale_ptr.release();
return ret;
}
但是,此版本不是异常安全的,因为如果release
引发异常,则不会调用set.erase
。我们可以通过确保调用unique_ptr
来滥用release
(!)来解决此问题,而不管该函数是正常退出还是异常退出:
template <typename T>
auto erase(std::unordered_set<std::unique_ptr<T>>& set, T* ptr)
{
std::unique_ptr<T> stale_ptr{ptr};
auto release = [](std::unique_ptr<T>* p) { p->release(); };
std::unique_ptr<std::unique_ptr<T>, decltype(release)> release_helper{&stale_ptr, release};
return set.erase(stale_ptr);
}