我最近在C ++ 11中了解了自定义分配器,并尝试在我的应用程序中使用它们。但是我遇到了一个段错误,可以通过以下最小例子重现:
#include <vector>
#include <unordered_map>
#include <scoped_allocator>
template<class T> struct custom_allocator {
typedef T value_type;
custom_allocator() noexcept {}
template <class U> custom_allocator (const custom_allocator<U>&) noexcept {}
T* allocate (std::size_t n) { return static_cast<T*>(::operator new(n*sizeof(T))); }
void deallocate (T* p, std::size_t n) { ::delete(p); }
template <typename U> constexpr bool operator==(const custom_allocator<U>&) const { return true; }
template <typename U> constexpr bool operator!=(const custom_allocator<U>&) const { return false; }
};
template<class T> using custom_scoped_allocator = std::scoped_allocator_adaptor<custom_allocator<T> >;
typedef std::unordered_map<int, int, std::hash<int>, std::equal_to<int>,
custom_scoped_allocator<std::pair<const int, int> > > MyMap;
typedef std::vector<MyMap, custom_scoped_allocator<MyMap> > MyVector;
int main() {
MyVector vec(1);
vec[0][0] = 0;
return 0;
}
自定义分配器正好是示例中建议的那个
http://www.cplusplus.com/reference/memory/allocator_traits/
然后将其与std::scoped_allocator_adaptor
结合使用,如我在互联网上的一些地方所建议的那样。
使用g++ -g3 -O0 -std=c++11 -march=core-avx-i -o tmpalloc tmpalloc.cpp
使用gcc 5.4.0编译代码。当我尝试运行它时,会报告以
*** Error in `./tmpalloc': double free or corruption (fasttop): 0x0000000000ae3c90 ***
如果我使用AddressSanitizer重新编译,我会得到有关双重免费的以下详细信息:https://pastebin.com/raw/xy2NQtD0 (对不起,对于pastebin,但它并不漂亮。) 基本上,unordered_map对象的析构函数似乎被调用了两次。
我做错了什么?
答案 0 :(得分:1)
您的allocate
函数分配了一堆字节,但不调用任何构造函数(通过直接调用operator new
全局函数)。您的deallocate
函数在类型指针上调用delete
,这会导致在调用全局operator delete
函数以释放内存之前调用该类型的析构函数。最终结果是你破坏了你没有构造的内存(在调用allocate
/ deallocate
函数之后/之前,调用者会处理构造和破坏。
您应该使用补充方法释放内存以分配它。在C ++ 14或更高版本中,这将是:
void deallocate (T* p, std::size_t n) { ::operator delete(p, n * sizeof(T)); }
其中n
的值传递给allocate
,第二个参数是传递给new
的值。在C ++ 14之前,只需转发到单个参数版本(这是默认的两个参数operator delete将执行的操作):
void deallocate (T* p, std::size_t n) { ::operator delete(p); }