std::unique_ptr 和 std::map
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
不会 append 元素,而是 sorts 它们.然而 emplace
returns 是它刚刚插入的迭代器,所以你只需要:
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())
条件,使其提前 return,但这只是个人喜好问题。
要不然你这个我觉得还不错
你将其标记为 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
函数将放置其参数。如果键已经存在,则不构造任何对象。在任何一种情况下,都会返回 key/value 对的迭代器。此函数避免了执行 find
-> emplace/insert
.
时涉及的双重查找
在我们的例子中,我们不能简单地传递 try_emplace
的参数,所以我试图聪明地使用这个 DelayedBar
class 延迟对象的构造.它仅在尝试转换为 std::unique_ptr<Bar>
时调用 CreateNewBar
,这仅在 try_emplace
尝试构造对象时发生。
我已经使用 GCC 8.2、Clang 7.0.0 和 MSVC 19.16(全部通过编译器资源管理器)编译了它并且编译正常。
我有一个 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
不会 append 元素,而是 sorts 它们.然而 emplace
returns 是它刚刚插入的迭代器,所以你只需要:
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())
条件,使其提前 return,但这只是个人喜好问题。
要不然你这个我觉得还不错
你将其标记为 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
函数将放置其参数。如果键已经存在,则不构造任何对象。在任何一种情况下,都会返回 key/value 对的迭代器。此函数避免了执行 find
-> emplace/insert
.
在我们的例子中,我们不能简单地传递 try_emplace
的参数,所以我试图聪明地使用这个 DelayedBar
class 延迟对象的构造.它仅在尝试转换为 std::unique_ptr<Bar>
时调用 CreateNewBar
,这仅在 try_emplace
尝试构造对象时发生。
我已经使用 GCC 8.2、Clang 7.0.0 和 MSVC 19.16(全部通过编译器资源管理器)编译了它并且编译正常。