且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

从unordered_set有效地擦除unique_ptr

更新时间: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);
}

实时演示