std :: unique_ptr与std :: map

时间:2019-02-22 14:01:39

标签: c++ c++14 smart-pointers stdmap

我有一个std::map,键是std::shared_ptr<Foo>,值是std::unique_ptr<Bar>,其中FooBar是与第三方截然不同的类图书馆。我将此std::map对象用作内存缓存。

我想知道,既然已经构造了传递到Bar的{​​{1}}了,那么从该方法中插入新条目然后从方法返回的最佳方法是什么?

我目前有以下内容:

std::unique_ptr

编辑

感谢昆汀提供的答案,现在是我的实现方式

class SomeClass
{
public:

    const Bar* TryGetBarValue(std::shared_ptr<Foo> foo)
    {
        auto it = _cache.find(foo);

        if(it == _cache.end())
        {
            Bar bar = ThirdPartLibrary::CreateBar();
            _cache.emplace(foo, std::make_unique<Bar>(bar));
            return _cache.rbegin()->second.get();
        }

        //return result as raw ptr from unique_ptr
        return it->second.get();
    }

private:
    std::map<std::shared_ptr<Foo>, std::unique_ptr<Bar>> _cache;
}

感谢您的所有帮助!

2 个答案:

答案 0 :(得分:1)

return _cache.rbegin()->second.get();不能满足您的要求,因为std::map不会附加元素,而是排序。但是emplace将迭代器返回到它刚刚插入的迭代器,因此您只需要:

return _cache.emplace(foo, std::make_unique<Bar>(bar))->first->second.get();

甚至,由于实际上不需要存储和复制Bar,因此您也可以牺牲foo

return _cache.emplace(
    std::move(foo),
    std::make_unique<Bar>(ThirdPartLibrary::CreateBar())
)->first->second.get();

我也将亲自翻转(it == _cache.end())条件以使其早日返回,但这只是个口味问题。

否则,你的东西对我来说很好。

答案 1 :(得分:0)

您将其标记为c ++ 14,但为后代,我将添加一个C ++ 17版本:

const Bar* TryGetBarValue(std::shared_ptr<Foo> foo)
{
    struct DelayedBar
    {
        operator std::unique_ptr<Bar>() const { return std::make_unique<Bar>(thirdpartyLibrary::CreateBar()); }
    };
    return _cache.try_emplace(std::move(foo), DelayedBar()).first->second.get();
}

如果地图尚未包含该键,则try_emplace函数将放置其参数。如果密钥已经存在,则不会构造任何对象。无论哪种情况,都会返回该键/值对的迭代器。此功能避免了在执行find-> emplace/insert时涉及的双重查询。

在我们的例子中,我们不能简单地传递try_emplace的参数,因此我试图聪明地延迟使用此DelayedBar类的对象的构造。仅在尝试转换为CreateNewBar时才会调用std::unique_ptr<Bar>,只有在try_emplace试图构造对象时才会发生。

我已经使用GCC 8.2,Clang 7.0.0和MSVC 19.16(都通过Compiler Explorer)对其进行了编译,并且可以编译。