[英]std::unique_ptr with std::map
我有一个std::map
,其中键是std::shared_ptr<Foo>
,值是std::unique_ptr<Bar>
,其中Foo
和Bar
是来自第三方库的非常不同的类。 我使用这个std::map
对象作为内存缓存。
我想知道在此映射中插入新条目然后从方法返回的最佳方法是什么,因为传入std::unique_ptr
的Bar
已经被构造?
我目前有以下几点:
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;
}
感谢你的帮助!
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())
条件以使其早日返回,但这只是品味问题。
否则,你所拥有的对我来说看起来不错。
您将其标记为 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
函数将try_emplace
其参数。 如果键已经存在,则不构造任何对象。 在任何一种情况下,都会返回该键/值对的迭代器。 当您确实find
-> emplace/insert
时,此功能避免了涉及的双重查找。
在我们的例子中,我们不能简单地传递try_emplace
的参数,所以我试图巧妙地使用这个DelayedBar
类延迟对象的构造。 它仅在尝试try_emplace
为std::unique_ptr<Bar>
时调用CreateNewBar
,这仅在try_emplace
尝试构造对象时发生。
我已经用 GCC 8.2、Clang 7.0.0 和 MSVC 19.16(全部通过编译器资源管理器)编译了它,它编译没问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.