有效地从无序集中擦除unique_ptr

问题描述 投票:2回答:1

我正在使用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。这放弃了unique_ptr提供的所有优点。
  • unordered_set::begin(key)查找存储桶。据我所知,我无法创建与要删除的unique_ptr相匹配的密钥。但是很高兴被证明是错误的(:
c++ c++14 unique-ptr unordered-set
1个回答
1
投票

这是一个艰难的情况。 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);
}
© www.soinside.com 2019 - 2024. All rights reserved.