简体   繁体   English

std::unique_ptr 与 std::map

[英]std::unique_ptr with std::map

I have a std::map where the key is std::shared_ptr<Foo> and the value is std::unique_ptr<Bar> where Foo and Bar are very different classes from a third-party library.我有一个std::map ,其中键是std::shared_ptr<Foo> ,值是std::unique_ptr<Bar> ,其中FooBar是来自第三方库的非常不同的类。 I am using this std::map object as an in-memory cache.我使用这个std::map对象作为内存缓存。

I am wondering what the best way of inserting a new entry into this map will be and then returned from a method, given that the Bar passed into the std::unique_ptr will already be constructed?我想知道在此映射中插入新条目然后从方法返回的最佳方法是什么,因为传入std::unique_ptrBar已经被构造?

I currently have the following:我目前有以下几点:

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;
}

EDIT编辑

Thanks to the answer provided by Quentin, this is now my implementation:感谢 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;
}

Thanks for all your help!感谢你的帮助!

return _cache.rbegin()->second.get(); does not do what you want, as std::map does not append elements but sorts them.不做你想做的,因为std::map追加元素而是对它们进行排序 However emplace returns an iterator to what it just inserted, so you only need:但是emplace将迭代器返回到它刚刚插入的内容,因此您只需要:

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

Or even, since you don't actually need to store and copy the Bar , and you can also sacrifice foo :甚至,由于您实际上并不需要存储和复制Bar ,您也可以牺牲foo

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

I'd also personally flip the (it == _cache.end()) condition to make it an early return, but that's just a matter of taste.我也会亲自翻转(it == _cache.end())条件以使其早日返回,但这只是品味问题。

Otherwise, what you have looks good to me.否则,你所拥有的对我来说看起来不错。

You tagged this as c++14, but for posterity I'll add a C++17 version:您将其标记为 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();
}

The try_emplace function will emplace its arguments if the map doesn't already contain that key.如果映射尚未包含该键,则try_emplace函数将try_emplace其参数。 If the key already exists, no object is constructed.如果键已经存在,则不构造任何对象。 In either case an iterator to that key/value pair is returned.在任何一种情况下,都会返回该键/值对的迭代器。 This function avoids the double lookup involved when you do find -> emplace/insert .当您确实find -> emplace/insert时,此功能避免了涉及的双重查找。

In our case we can't simply pass the arguments of try_emplace along so I've tried to be clever in delaying the construction of the object using this DelayedBar class.在我们的例子中,我们不能简单地传递try_emplace的参数,所以我试图巧妙地使用这个DelayedBar类延迟对象的构造。 It only calls CreateNewBar when trying to cast to a std::unique_ptr<Bar> which only happens when try_emplace is trying to construct the object.它仅在尝试try_emplacestd::unique_ptr<Bar>时调用CreateNewBar ,这仅在try_emplace尝试构造对象时发生。

I have compiled this with GCC 8.2, Clang 7.0.0 and MSVC 19.16 (all via Compiler Explorer) and it compiles okay.我已经用 GCC 8.2、Clang 7.0.0 和 MSVC 19.16(全部通过编译器资源管理器)编译了它,它编译没问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM