带有std :: map的std :: unique_ptr

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

我有一个std::map,关键是std::shared_ptr<Foo>,值是std::unique_ptr<Bar>,其中FooBar是与第三方库非常不同的类。我使用这个std::map对象作为内存缓存。

我想知道在这个地图中插入新条目的最佳方法是什么,然后从方法返回,因为传入Barstd::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;
}

编辑

感谢Quentin提供的答案,现在我的实现:

class SomeClass
{
public:

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

        if (it != _cachedImages.end())
        {
            return it->second.get();
        }

        return _cachedImages.emplace(
                std::move(texture), 
                std::make_unique<sf::Image>(texture->copyToImage())
            ).first->second.get(); 
        }

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

感谢你的帮助!

c++ c++14 smart-pointers stdmap
2个回答
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())条件,使其成为早期回归,但这只是一个品味问题。

否则,你对我看起来很好。


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编译了这个(所有这些都通过编译器资源管理器)编译好了。

© www.soinside.com 2019 - 2024. All rights reserved.