Stephen Lavavej 的 Mallocator 在 C++11 中是否相同?
Is Stephen Lavavej's Mallocator the same in C++11?
8 年前,Stephen Lavavej 发布了 this blog post,其中包含一个名为 "Mallocator" 的简单分配器实现。从那时起,我们已经过渡到 C++11 时代(很快就是 C++17)……新的语言特性和规则是否会影响 Mallocator,或者它是否仍然相关?
正如@kerrek 所建议的,这是一个基于 linked arena 分配器的 Mallocator,删除了 arena 部分。
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;
}
};
代码少了很多。传播的一些特征。
STL 在 CppCon 2014(26 分 30 秒开始)的 STL Features and Implementation techniques 演讲中回答了这个问题。
slides 在 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);
}
};
请注意,它正确处理了分配中可能出现的溢出。
8 年前,Stephen Lavavej 发布了 this blog post,其中包含一个名为 "Mallocator" 的简单分配器实现。从那时起,我们已经过渡到 C++11 时代(很快就是 C++17)……新的语言特性和规则是否会影响 Mallocator,或者它是否仍然相关?
正如@kerrek 所建议的,这是一个基于 linked arena 分配器的 Mallocator,删除了 arena 部分。
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;
}
};
代码少了很多。传播的一些特征。
STL 在 CppCon 2014(26 分 30 秒开始)的 STL Features and Implementation techniques 演讲中回答了这个问题。
slides 在 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);
}
};
请注意,它正确处理了分配中可能出现的溢出。