我有一个std::map
,键是std::shared_ptr<Foo>
,值是std::unique_ptr<Bar>
,其中Foo
和Bar
是与第三方截然不同的类图书馆。我将此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;
}
感谢您的所有帮助!
答案 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)对其进行了编译,并且可以编译。