自定义分配器仅在 VS 2015 中以发布模式编译
Custom allocator only compiles in Release mode in VS 2015
我为 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();
}
};
}
有人知道为什么会出现此错误吗?我该如何解决?
你的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;
满足分配器要求的类型不必具有 reference
和 const_reference
,因此通过添加这些 typedef,您可以确保您的分配器只能与分配器的一个子集一起工作。如果您认为需要它们,只需按照 std::allocator
的方式定义它们即可:
typedef value_type& reference;
typedef const value_type& const_reference;
我为 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();
}
};
}
有人知道为什么会出现此错误吗?我该如何解决?
你的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;
满足分配器要求的类型不必具有 reference
和 const_reference
,因此通过添加这些 typedef,您可以确保您的分配器只能与分配器的一个子集一起工作。如果您认为需要它们,只需按照 std::allocator
的方式定义它们即可:
typedef value_type& reference;
typedef const value_type& const_reference;