我编写了一个自定义的线性分配器,我正在与向量一起使用。分配器可以将另一个分配器作为模板/构造函数参数来分配其初始存储。现在它使用 std::分配器进行初始分配就很好了,但是当我溢出向量时,它不会给出错误。我知道这是未定义的行为,所以我不能保证段错误,但它始终允许我从向量(大小为 64(的开头修改 1037600 个元素。
我打印并修改了每个元素,直到它给我一个错误:
template <class T, size_t N, class Alloc = std::allocator<uint8_t>>
class LinearAllocator
{
public:
typedef T value_type;
LinearAllocator()
:m_memory{m_alloc.allocate(N)}, m_head{m_memory}
{
}
template<class U>
LinearAllocator(LinearAllocator<U, N> const& other) noexcept
:m_memory{other.m_memory}, m_head{other.m_head}
{}
template<class U>
bool operator==(LinearAllocator<U, N> const& other) const noexcept
{
return m_memory == other.m_memory && m_head == other.m_head;
}
template<class U>
bool operator!=(LinearAllocator<U, N> const& other) const noexcept
{
return !(*this == other);
}
T* allocate(const size_t n)
{
uint8_t* memory = static_cast<uint8_t*>(m_memory);
uint8_t* head = static_cast<uint8_t*>(m_head);
if(n == 0)
{
return nullptr;
}
if(n > static_cast<size_t>(-1) / sizeof(T))
{
throw std::bad_array_new_length();
}
if(n > N) { throw std::bad_alloc(); }
if(memory + N < head + n) { head = memory; }
void* pv = m_head;
head += n;
m_head = static_cast<void*>(head);
return static_cast<T*>(pv);
}
void deallocate(T* const p, size_t) const noexcept
{}
private:
Alloc m_alloc = Alloc();
void* m_memory = nullptr;
void* m_head = nullptr;
};
int main()
{
std::vector<uint8_t, LinearAllocator<uint8_t, 64>> vec(64, 1);
//std::vector<uint8_t> vec(65, 1);
std::cout << (void*)vec.data() << std::endl;
for(size_t i = 0; i < vec.size()+10000000; ++i)
{
std::cout << i << " " << (int)vec[i]++ << " " << (int)vec[i]<< "n";
}
}
我预计这会在元素 64 溢出时失败,因为我认为这是堆分配的内存。但它似乎在同一点上失败了,元素1037663,远远超出了我的预期。具体说来:
$ ./运行
0 1 2
11 2
。
1037662 0 1
1037663 0 1
分段错误:11
最可能的原因是当你从std::allocator
分配空间时,它从操作系统中获取了足够的内存来容纳1037663元素。 当操作系统注意到你要求查看尚未授予程序访问权限的内存地址时,会发生分段错误。 std::allocator
已要求操作系统提供其他内存,因此操作系统不会注意到何时超出vector
的边界,直到您超出提供给std::allocator
的内存范围。