使用自定义分配器的Std::unordered_set

std::unordered_set with custom allocator

本文关键字:unordered set Std 自定义 分配器      更新时间:2023-10-16

晚上好

解决方案:问题来自于我的分配器的显式关键字。

编辑:我终于找到了问题所在。它似乎来自unordered_set的move函数,当它与一些自定义分配器一起使用时。还挖。

编辑:奇怪的是,当使用我的自定义分配器和std::vector时没有问题。

为什么当我尝试从

复制元素时得到错误消息?
typedef std::unordered_set< const CScopeProfiler* > CInternalScopeProfilersSet;

:

typedef std::unordered_set< const CScopeProfiler*, std::hash< const CScopeProfiler* >, std::equal_to< const CScopeProfiler* >, CAllocator< const CScopeProfiler* > > CScopeProfilersSet;

如下:

CProfiler::CScopeProfilersSet CProfiler::ScopeProfilersRegistry() const
{
    CScopeProfilersSet kSet;
    kSet.insert( *( m_pkRegister->begin() ) );
    return kSet;
}

准确的错误信息是用法语给出的,所以大概的翻译是:

Error 1 error C2664: 'std::_Hash<_Traits>::_Hash(const std::_Uhash_compare<_Kty,_Hasher,_Keyeq> &,const GameForge::Core::CAllocator<T> &)' : impossible to convert second parameter of 'std::_Wrap_alloc<_Alloc>' to 'const GameForge::Core::CAllocator<T> &'   c:program files (x86)microsoft visual studio 11.0vcincludeunordered_set    195 1

请注意,如果我不放入kSet.insert(),我不会得到错误。

类型定义是在CProfiler的范围内完成的。

我已经被困了好几天了,它似乎不像人们想象的那样来自hasher。任何想法都是欢迎的,很抱歉,如果这篇文章不是很好,因为这是我在StackOverflow上的第一篇文章。

PS:按要求这里是代码片段。

namespace GameForge
{
    namespace Core
    {
        class CAllocationsHistogram;
        // Ensure profiling code isn't profiled.
        class GF_API CProfiler
        {
        public:
            class CScopeRun;
            class GF_API CScopeProfiler
            {
                friend CProfiler;
                friend CScopeRun;
            public:
                CScopeProfiler( const char* pcLabel );
                ~CScopeProfiler();
            };
            class GF_API CScopeRun
            {
                friend CProfiler;
            public:
                CScopeRun( CScopeProfiler& rkScopeProfiler );
                ~CScopeRun();
            };
            typedef std::unordered_set< const CScopeProfiler*,
                                        std::hash< const CScopeProfiler* >,
                                        std::equal_to< const CScopeProfiler* >,
                                        CAllocator< const CScopeProfiler* > > CScopeProfilersSet;
        private:
            typedef std::unordered_set< const CScopeProfiler* > CInternalScopeProfilersSet;
        public:
            CScopeProfilersSet ScopeProfilersRegistry() const;
        protected:
            CProfiler();
            ~CProfiler();
        private:
            CInternalScopeProfilersSet* m_pkRegister;
        };

因为,不幸的是,您的两个容器是不同的类型。因此,它们的迭代器也是如此。这个问题正是吓人迭代器的设计目的——当容器应该被视为迭代目的的等效时,即使它们的类型不同。解决方法是统一容器类型(可能从另一个容器类型派生),或者重写以不依赖于基于迭代器的算法(分别解引用和复制元素)。

编辑:

我能够用一个简单的示例进行再现,该示例与insert()调用无关,而是与临时kSet的右值移动函数有关。在c++ 11中,对自定义分配器有一些新的要求——特别是重新绑定类型函数。更多信息请看这里

template<typename T>
struct CAllocator : allocator<T>
{
    CAllocator(){}
    template <class U>
    CAllocator(CAllocator<U> const &) {}
    // This required to ensure custom allocator is propagated in move semantics
    template <class U>
    struct rebind
    {
        typedef CAllocator<U> other;
    };
};
typedef std::unordered_set< const CScopeProfiler*, std::hash< const CScopeProfiler* >, std::equal_to< const CScopeProfiler* >, CAllocator< const CScopeProfiler * > >  CScopeProfilersSet;
CScopeProfilersSet ScopeProfilersRegistry()
{
    CScopeProfilersSet kSet;
    return kSet;
};