更新时间:2023-11-10 09:36:52
这是擦除
有一个重载,该重载带有 const key_type&
参数,因此我们可以尝试创建一个过期 unique_ptr
来获取要删除的元素的哈希值:
This is a tough case. erase
has an overload that takes a const key_type&
parameter, so we can try to create a "stale" unique_ptr
to get the hash value of the element to be erased:
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;
}
(实时演示)
但是,此版本在一般,因为如果 set.erase
引发异常,则不会调用 release
。在这种情况下这不是问题,因为 std :: equal_to< std :: unique_ptr< T>> :: operator()
永远不会引发异常。在一般情况下,我们可以通过确保调用 release
来滥用 unique_ptr
(!)来强制异常安全。该函数是正常还是异常退出:
This version, however, is not exception safe in general, because release
will not be called if set.erase
throws an exception. This is not a problem in this case, since std::equal_to<std::unique_ptr<T>>::operator()
never throws exception. In the general case, we can abuse unique_ptr
(!) to enforce exception safety by ensuring that release
is called regardless of whether the function is exited normally or exceptionally:
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);
}
(实时演示)