Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::unique_ptr与std::map_C++_C++14_Smart Pointers_Stdmap - Fatal编程技术网

C++ std::unique_ptr与std::map

C++ std::unique_ptr与std::map,c++,c++14,smart-pointers,stdmap,C++,C++14,Smart Pointers,Stdmap,我有一个std::map,其中键是std::shared\u ptr,值是std::unique\u ptr,其中Foo和Bar是与第三方库非常不同的类。我使用这个std::map对象作为内存缓存 我想知道,如果传递到std::unique_ptr中的Bar已经被构造,那么将新条目插入该映射并从方法返回的最佳方式是什么 我目前有以下情况: class SomeClass { public: const Bar* TryGetBarValue(std::shared_ptr<Foo

我有一个
std::map
,其中键是
std::shared\u ptr
,值是
std::unique\u ptr
,其中
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;
}
class-SomeClass
{
公众:
常数条*TryGetBarValue(标准::共享\u ptr foo)
{
autoit=\u cache.find(foo);
if(it==\u cache.end())
{
Bar Bar=ThirdPartLibrary::CreateBar();
_放置(foo,std::make_unique(bar));
return _cache.rbegin()->second.get();
}
//将结果作为原始ptr从唯一ptr返回
返回它->秒。获取();
}
私人:
std::map\u缓存;
}
编辑

多亏了昆汀提供的答案,这就是我的实现:

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;
}
class-SomeClass
{
公众:
常数条*TryGetBarValue(标准::共享\u ptr foo)
{
auto it=\u cachedImages.find(纹理);
if(it!=\u cachedImages.end())
{
返回它->秒。获取();
}
返回_cachedImages.emplace(
标准::移动(纹理),
std::make_unique(纹理->复制图像())
).first->second.get();
}
私人:
std::map\u缓存;
}
谢谢你的帮助

返回_cache.rbegin()->second.get()不执行您想要的操作,因为
std::map
不追加元素,而是对它们进行排序。但是,
emplace
将迭代器返回到刚插入的内容,因此您只需要:

return _cache.emplace(foo, std::make_unique<Bar>(bar))->first->second.get();
我个人也会翻转
(it==\u 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();
}
const Bar*TryGetBarValue(标准::共享\u ptr foo)
{
结构延迟条
{
运算符std::unique_ptr()const{return std::make_unique(第三方库::CreateBar());}
};
返回_cache.try_emplace(std::move(foo),DelayedBar()).first->second.get();
}
如果映射尚未包含该键,
try\u emplace
函数将放置其参数。如果密钥已存在,则不会构造任何对象。在任何一种情况下,都会返回该键/值对的迭代器。此函数可避免执行
查找
->
放置/插入
时所涉及的双重查找

在我们的例子中,我们不能简单地传递
try\u emplace
的参数,因此我尝试聪明地使用这个
DelayedBar
类延迟对象的构造。它仅在尝试强制转换到
std::unique_ptr
时调用
CreateNewBar
,这仅在
try_emplace
尝试构造对象时发生


我已经用GCC 8.2、Clang 7.0.0和MSVC 19.16(全部通过编译器资源管理器)编译了这篇文章,它编译得很好。

没有直接关系,但是你为Foo和Bar创建了哈希函数吗?那
unique\u ptr
可以为空吗?它真的需要分享
Foo
的所有权吗?在99%的情况下,共享的ptr是设计糟糕的标志
可能是错误的,因为在
std::map
中,元素按照
std::less
的顺序插入。因此,新插入的元素不太可能位于
rbegin()
位置。如果您使用唯一性来表示唯一性,我在这里尝试进行构造,我真的看不到返回原始指针的意义。如果您需要共享访问权限,那么使用共享的访问权限,并将它们与您需要的任何类连接起来。如果你想确保唯一性,那么移动/擦除就不是原始的了?@Ælex“unique”指的是所有者的数量,而不是观察者的数量。我唯一能看到的就是可能做
std::make_unique(std::move(bar))
,以防移动构造函数比复制构造函数做得更好。@sirgue的确,在答案中补充了这一点:)接受了这个答案,这正是我一直在寻找的,感谢您对rbegin()的介绍,我将根据您的建议更改它。多余的副本也适用于密钥。移动
foo
就足够了。在共享指针的情况下,我们知道移动更有效。
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();
}