0

我编写了一个简单的虚拟分配器,vector<>以便可以vector<>用作堆栈数组的包装器,如下所示:

#include <vector>
#include "stdio.h"
#include "stack_allocator.h"

using namespace std;

int main() {
    int buffer[100];
    vector<int, StackAllocator<int>> v((StackAllocator<int>(buffer, 100)));
    v.push_back(2);
    printf("%d", v[0]);
    v.pop_back();
}

但是,仅在VS2015 的调试模式下,我收到以下编译器错误:

'std::StackAllocator<T2, std::allocator<T>>::StackAllocator(std::StackAllocator<T, std::allocator<T>> &&)':
   cannot convert argument 1 from
      'std::_Wrap_alloc<std::StackAllocator<int,std::allocator<T>>>'
   to
      'const std::allocator<T>&'
in "c:\program files (x86)\microsoft visual studio 14.0\vc\include\xmemory0" at line 952

但是,编译和执行在发布模式下按预期工作。

这里是stack_allocator.h

#pragma once

#include <functional>

namespace std {
    template <typename T, typename Allocator = allocator<T>>
    class StackAllocator {
    public:
        typedef typename allocator_traits<Allocator>::value_type value_type;
        typedef typename allocator_traits<Allocator>::pointer pointer;
        typedef typename allocator_traits<Allocator>::const_pointer const_pointer;
        typedef typename allocator_traits<Allocator>::size_type size_type;
        typedef typename allocator_traits<Allocator>::difference_type difference_type;
        typedef typename allocator_traits<Allocator>::const_void_pointer const_void_pointer;
        typedef typename Allocator::reference reference;
        typedef typename Allocator::const_reference const_reference;

        template<typename T2>
        struct rebind {
            typedef StackAllocator<T2> other;
        };

    private:
        size_t m_size;
        Allocator m_allocator;
        pointer m_begin;
        pointer m_end;
        pointer m_stack_pointer;

        bool pointer_to_internal_buffer(const_pointer p) const {
            return (!(less<const_pointer>()(p, m_begin)) && (less<const_pointer>()(p, m_end)));
        }

    public:
        StackAllocator(const Allocator& alloc = Allocator()) noexcept :
            m_size(0),
            m_allocator(alloc),
            m_begin(nullptr),
            m_end(nullptr),
            m_stack_pointer(nullptr) {
        }

        StackAllocator(pointer buffer, size_t size, const Allocator& alloc = Allocator()) noexcept :
            m_size(size),
            m_allocator(alloc),
            m_begin(buffer),
            m_end(buffer + size),
            m_stack_pointer(buffer) {
        }

        template <typename T2>
        StackAllocator(const StackAllocator<T2, Allocator>& other) noexcept :
            m_size(other.m_size),
            m_allocator(other.m_allocator),
            m_begin(other.m_begin),
            m_end(other.m_end),
            m_stack_pointer(other.m_stack_pointer) {
        }

        pointer allocate(size_type n, const_void_pointer hint = const_void_pointer()) {
            if (n <= size_type(distance(m_stack_pointer, m_end))) {
                pointer result = m_stack_pointer;
                m_stack_pointer += n;
                return result;
            }
            else
                return m_allocator.allocate(n, hint);
        }

        void deallocate(pointer p, size_type n) {
            if (pointer_to_internal_buffer(p))
                m_stack_pointer -= n;
            else
                m_allocator.deallocate(p, n);
        }

        size_type capacity() const noexcept {
            return m_size;
        }

        size_type max_size() const noexcept {
            return m_size;
        }

        pointer address(reference x) const noexcept {
            if (pointer_to_internal_buffer(addressof(x)))
                return addressof(x);
            else
                return m_allocator.address(x);
        }

        const_pointer address(const_reference x) const noexcept {
            if (pointer_to_internal_buffer(addressof(x)))
                return addressof(x);
            else
                return m_allocator.address(x);
        }

        pointer buffer() const noexcept {
            return m_begin;
        }

        template <typename T2, typename... Args>
        void construct(T2* p, Args&&... args) {
            m_allocator.construct(p, forward<Args>(args)...);
        }

        template <typename T2>
        void destroy(T2* p) {
            m_allocator.destroy(p);
        }

        template <typename T2>
        bool operator==(const StackAllocator<T2, Allocator>& other) const noexcept {
            return buffer() == other.buffer();
        }

        template <typename T2>
        bool operator!=(const StackAllocator<T2, Allocator>& other) const noexcept {
            return buffer() != other.buffer();
        }
    };
}

有人知道为什么会发生此错误吗?我该如何解决?

4

1 回答 1

1

rebind的坏了,应该是:

template<typename T2>
    struct rebind {
        using Alloc2
          = typename allocator_traits<Allocator>::rebind_alloc<T2>;
        using other = StackAllocator<T2, Alloc2>;
    };

否则,重新绑定总是使用与当前参数std::allocator<T2>无关的东西来创建一些东西。Allocator

例如,如果你实例化StackAllocator<int, SomeAlloc<int>然后重新绑定它,long你会得到StackAllocator<long, std::allocator<long>>一个完全不同的类型。

我认为 VC++ 调试模式是通过重新绑定你的来创建某种包装器分配器,并且由于你损坏的rebind.

此外,这些行是一个问题:

    typedef typename Allocator::reference reference;
    typedef typename Allocator::const_reference const_reference;

满足分配器要求的类型不必具有referenceconst_reference因此通过添加这些 typedef,您可以确保您的分配器只能与分配器的子集一起使用。如果您认为需要它们,只需按照相同的方式定义它们std::allocator

    typedef value_type& reference;
    typedef const value_type& const_reference;
于 2017-04-04T14:31:27.170 回答