C++ std::带有自定义分配器的无序_集

C++ std::带有自定义分配器的无序_集,c++,stl,C++,Stl,晚上好, 解决方案:问题来自我的分配器中的explicit关键字 编辑:我终于找到了问题所在。当它与一些自定义分配器一起使用时,它似乎来自无序_集的move-ctor。还在挖 编辑:奇怪的是,在使用我的自定义分配器和std::vector时并没有问题 为什么在尝试从以下位置复制元素时会收到错误消息: typedef std::unordered_set< const CScopeProfiler* > CInternalScopeProfilersSet; 准确的错误信息以法语给出

晚上好,

解决方案:问题来自我的分配器中的explicit关键字

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

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

为什么在尝试从以下位置复制元素时会收到错误消息:

typedef std::unordered_set< const CScopeProfiler* > CInternalScopeProfilersSet;
准确的错误信息以法语给出,因此近似翻译为:

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.0\vc\include\unordered_set    195 1
Error 1 Error C2664:'std::_Hash::_Hash(const std:_Uhash&,const GameForge::Core::CAllocator&'):无法将'std:_Wrap_alloc'的第二个参数转换为'const GameForge::Core::CAllocator&'c:\program files(x86)\microsoft visual studio 11.0\vc\include\unordered\unordered\u set 195 1
请注意,如果不放置kSet.insert(),则不会出现错误

TypeDef在CProfiler的范围内完成

我已经被困了好几天了,它似乎不像人们所期望的那样来自散列程序。任何想法都是欢迎的,很抱歉,如果这篇文章的格式不正确,因为这是我在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;
        };
namespace GameForge
{
名称空间核心
{
类调用位置直方图;
//确保未对分析代码进行分析。
类GF_API CProfiler
{
公众:
计算机类;
类GF_API CScopeProfiler
{
朋友CProfiler;
科普伦之友;
公众:
CScopeProfiler(const char*pcLabel);
~CScopeProfiler();
};
类GF_API CSOperatun
{
朋友CProfiler;
公众:
CScopeRun(CScopeProfiler&rkScopeProfiler);
~cscopun();
};
typedef std::无序_集,
标准::等于,
CAllocator>CScopeProfilersSet;
私人:
typedef std::无序_集cinternalscopeprofilers集;
公众:
CScopeProfilerSet ScopeProfilersRegistry()常量;
受保护的:
CProfiler();
~CProfiler();
私人:
CinternalScopeProfilerSet*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;
};
模板
结构调用器:分配器
{
CAllocator(){}
模板
CAllocator(callocatorconst&){
//这是确保在移动语义中传播自定义分配器所必需的
模板
结构重新绑定
{
类型定义调用器或其他;
};
};
typedef std::无序_集,std::等于,CAllocator>CScopeProfilersSet;
CScopeProfilerSet ScopeProfilersRegistry()
{
CScopeProfilersSet-kSet;
返回kSet;
};

我不相信,请发布一个最小的、完整的代码片段来展示这种行为……重点是最小的代码。我不太理解这一点,发布最小的代码非常困难。这是调试的一个重要部分:逐步减少代码,直到不再产生错误。这就是问题所在在我看来,最小值。代码实际上并没有传递迭代器,而是传递(引用)值。这是真的——对于不完整的代码,我假设取消引用可能是一个错误,并且出现了编译器错误msg,这表明分配器类型(一个是STL默认类型,另一个是自定义类型)之间直接不匹配,表示容器类型不匹配。@Adrian-如果将内容分开会发生什么:auto&elem=*(m_pkRegister->begin());kSet.insert(elem);我的分配器实际定义了重新绑定结构,如下所示,
templatestruct-rebind{typedef CAllocatorother;}
我现在无法测试,但我的分配器不是从std::allocator继承的,因为我知道任何类都可以是分配器,只要它能够满足接口要求。我发现CAllocator中的两个构造函数也是必要的-我没有进一步深入研究VC++11实现(分配器特性,等等).我建议您将我的框架与您的实现合并,可能分阶段进行。
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;
        };
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;
};