C++ 是斯蒂芬·拉瓦维';s Mallocator与C+中的相同+;11?
8年前,Stephen Lavavej发表了一篇包含一个简单分配器实现的文章,名为“Mallocator”。从那时起,我们已经过渡到C++11(很快就是C++17)时代。。。新的语言功能和规则是否影响了Mallocator,或者它仍然是相关的?正如@kerrek所建议的,这里是一个基于arena分配器的Mallocator,删除了arena部分C++ 是斯蒂芬·拉瓦维';s Mallocator与C+中的相同+;11?,c++,c++11,containers,c++-standard-library,allocator,C++,C++11,Containers,C++ Standard Library,Allocator,8年前,Stephen Lavavej发表了一篇包含一个简单分配器实现的文章,名为“Mallocator”。从那时起,我们已经过渡到C++11(很快就是C++17)时代。。。新的语言功能和规则是否影响了Mallocator,或者它仍然是相关的?正如@kerrek所建议的,这里是一个基于arena分配器的Mallocator,删除了arena部分 template<class T> struct Mallocator11 { using value_type = T; usin
template<class T>
struct Mallocator11 {
using value_type = T;
using pointer = T*;
using propagate_on_container_copy_assignment = std::true_type;
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
Mallocator11(Mallocator11 const&) = default;
Mallocator11& operator=(Mallocator11 const&) = default;
Mallocator11()=default;
template<class U>
Mallocator11(Mallocator11<U> const&) noexcept {}
template<class U>
Mallocator11& operator=(Mallocator11<U> const&) noexcept {return *this}
pointer allocate(std::size_t n) {
if (std::size_t(-1) / sizeof(T) < n)
throw std::bad_array_new_length(); // or something else
if (!n) return nullptr; // zero means null, not throw
if(auto*r= static_cast<pointer>(malloc(n * sizeof(T))))
return r;
throw std::bad_alloc();
}
void deallocate(pointer p, std::size_t n) {
free(p);
}
template<class U>
bool operator==(Mallocator11<U> const& rhs) const {
return true;
}
template<class U>
bool operator!=(Mallocator11<U> const& rhs) const {
return false;
}
};
模板
结构Mallocator11{
使用值_type=T;
使用指针=T*;
在容器上使用propagate\u\u copy\u assignment=std::true\u type;
在容器上使用propagate\u\u move\u assignment=std::true\u type;
在容器上使用propagate\u\u swap=std::true\u type;
Mallocator11(Mallocator11常量&)=默认值;
Mallocator11&运算符=(Mallocator11常量&)=默认值;
Mallocator11()=默认值;
模板
Mallocator11(Mallocator11常量&)noexcept{}
模板
Mallocator11&运算符=(Mallocator11常量&)noexcept{return*this}
指针分配(标准::大小\u t n){
如果(标准:尺寸t(-1)/sizeof(t)
更少的代码。传播的一些特点。STL本人在2014年CppCon的演讲中(从26'30开始)回答了这个问题 这些都在github上 我将幻灯片28和29的内容合并到下面:
#include <stdlib.h> // size_t, malloc, free
#include <new> // bad_alloc, bad_array_new_length
template <class T> struct Mallocator {
typedef T value_type;
Mallocator() noexcept { } // default ctor not required
template <class U> Mallocator(const Mallocator<U>&) noexcept { }
template <class U> bool operator==(
const Mallocator<U>&) const noexcept { return true; }
template <class U> bool operator!=(
const Mallocator<U>&) const noexcept { return false; }
T * allocate(const size_t n) const {
if (n == 0) { return nullptr; }
if (n > static_cast<size_t>(-1) / sizeof(T)) {
throw std::bad_array_new_length();
}
void * const pv = malloc(n * sizeof(T));
if (!pv) { throw std::bad_alloc(); }
return static_cast<T *>(pv);
}
void deallocate(T * const p, size_t) const noexcept {
free(p);
}
};
#包括//size\u t、malloc、免费
#包括//bad\u alloc、bad\u数组\u新长度
模板结构Mallocator{
类型定义T值_类型;
Mallocator()noexcept{}//默认构造函数不是必需的
模板Mallocator(const Mallocator&)noexcept{}
模板布尔算子==(
常量Mallocator&)常量noexcept{return true;}
模板布尔运算符=(
常量Mallocator&)常量noexcept{return false;}
分配(常数大小)常数{
如果(n==0){return nullptr;}
如果(n>静态_-cast(-1)/sizeof(T)){
抛出std::坏数组\新长度();
}
void*const pv=malloc(n*sizeof(T));
如果(!pv){throw std::bad_alloc();}
返回静态_-cast(pv);
}
无效解除分配(T*常数p,大小_T)常数无例外{
自由基(p);
}
};
请注意,它正确处理分配中可能出现的溢出。现在简单多了。@KerrekSB:Link?解释?也许看看下面的分配器示例,用
malloc
/free
。@KerrekSB:那么,不再有construct()
?不,construct
作为分配器特性的一部分,现在有了默认实现。如果需要它执行非默认操作(例如作用域分配程序
所做的操作),则可以指定它。分配
需要抛出错误;它不能返回null。friend
声明和交叉类型赋值是无关的。如果(std::size_t(-1)/sizeof(t)将是一个好主意在中分配以避免缓冲区溢出。还有@T.C.说了些什么。@KerrekSB还没有。一些集装箱要求仍在POCMA中说明。同时,总是等于
对于空的分配器已经是真的了。@Arnaud“可以有意义地传递给分配
”的最大值与“可以传递给分配而不引起异常的最大值”不同。需求字面上说是分配(max\u size()+2)
没有任何意义。@Elkvis没有;大小\u t保证为无符号,对于某些n
,无符号保证为数学模2^n
。因此,无符号类型(-1)
始终是任何无符号类型的最大值。作为一个小小的奖励,它不需要在其中包含具有数值限制的标准头文件。它应该是std::numeric\u limits::max()
而不是静态转换(-1)
尽管如此?@einpoklum标准保证是相同的:size\u不必遵守mod 2^N算法,其中N是size\u t的位数。使用后者而不是前者仍然是不好的编码方式。@einpoklum我同意。@einpoklum我认为std::list
需要定义分配器的其他方法,如重新绑定
。