我尝试在Kubuntu 20操作系统上使用gcc-12将我的代码从C11标准升级到C20。我有一个自定义分配器:
namespace allocators {
template <class T,int n = 16384>
class ListAllocator : public std::allocator<T> {
public:
typedef typename std::allocator<T>::size_type size_type;
typedef typename std::allocator<T>::pointer pointer;
public:
ListAllocator() : allocator<T>() {}
ListAllocator(const ListAllocator<T,n>& a) : std::allocator<T>(a) {}
ListAllocator(const allocator<T>& a) : std::allocator<T>(a) {}
char* _Charalloc(size_type N) {
if (idx==0)
return allocator<T>::_Charalloc(N);
else
return reinterpret_cast<char*>(arena[--idx]);
}
void deallocate(void* p, size_type s) {
if (idx == n)
allocator<T>::deallocate(p,s);
else
arena[idx++] = p;
}
static void deallocate() {
while(idx)
((allocator<T>*)0)->deallocate( reinterpret_cast<typename std::allocator<T>::pointer>(arena[--idx]) , size_type(sizeof(T)) );
}
static void* arena[n];
static size_t idx; // index of 1st emty field in arena
};
template <class T,int n> void* ListAllocator<T,n>::arena[n];
template <class T,int n> size_t ListAllocator<T,n>::idx;
}
我有一个结构体,包含以下内容:
typedef T Coord;
typedef std::pair<Coord , Coord > Point;
typedef ListAllocator<Point> ListPointAllocator;
typedef std::list<Point2d,ListPointAllocator > Pl;
Pl* plPtr;
Point & edgeRef() { return beg ? plPtr->front() : plPtr->back();}
我得到错误:class std::__cxx11::list<std::pair<int, int>, std::ListAllocator<std::pair<int, int>, 16384> >'} has no member named 'front' class std::__cxx11::list<std::pair<int, int>, std::ListAllocator<std::pair<int, int>, 16384> >'} has no member named 'back'
我想找个解释,但什么也没找到。到底是什么问题呢?
1条答案
按热度按时间yacmzcpb1#
您的分配器不满足Allocator要求。
如果不这样做,那么将其用作标准库模板的分配器会有未定义的行为,编译失败是比较幸运的结果之一。
一些问题:
1.您的分配器是从一个具有非类型模板参数的模板示例化的。因此没有提供默认的
rebind<U>
成员模板,您需要自己提供它。请注意,自C20起,std::allocator
不再提供rebind
。在C20之前,您的分配器确实从它继承了rebind
,但它会重新绑定到std::allocator<U>
,这是错误的。技术上是UB,并且可能导致您的自定义分配函数实际上没有被使用。不要从std::allocator
继承,这是不必要的。Allocator 所需的大多数功能都是通过std::allocator_traits
默认的。因此,最小的 Allocator 只需要提供构造函数value_type
、allocate
、deallocate
和operator==
(在C++20之前还有operator!=
)。在您的情况下,rebind
也是必需的,正如我上面解释的。_Charalloc
是全局保留标识符,因为它以下划线开头,后跟大写字母。您不能使用它。分配器应改为定义allocate
成员函数,类似于std::allocator::allocate
。allocator<T>::_Charalloc
是标准库的一个实现细节。你不应该使用它。如果你想引用底层分配器的分配,使用std::allocator_traits<std::allocator<T>>::allocate
或直接使用::operator new
。1.您的分配器不会检查各个分配的大小是否相同。无法保证
allocate
不会以不同的大小作为参数被调用。此外,在重新绑定之后,可能会对不同的类型进行不同的对齐。因此,您也不能在不检查对齐要求的情况下重用旧的分配。1.您需要
template<typename U> ListAllocator(const ListAllocator<U,n>&);
的构造函数。