自定义分配器仅在VS 2015中的发布模式下编译

时间:2017-02-11 14:34:03

标签: c++ visual-studio vector allocator debug-mode

我为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();
        }
    };
}

任何人都知道为什么会出现这种错误?我该如何解决?

1 个答案:

答案 0 :(得分: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参数无关的内容。

e.g。如果您实例化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;