0
我製作了一個簡單的堆棧分配器,可用於在堆棧上分配小容器。 我一直在使用這個類一段時間,它一直工作正常。 但是,今天我又切換了調試迭代器(_ITERATOR_DEBUG_LEVEL=2
),並且在由此開關激活的調試代碼中突然出現訪問衝突。啓用MSVC調試迭代器時堆棧分配器訪問衝突
模板編程和標準庫編碼約定的混合使得這非常難以調試,而且我也不完全是分配器方面的專家。我違反了分配器的某種規則嗎?
下面的代碼應該能夠重現錯誤。
#include <memory>
#include <vector>
template <typename T, size_t N, template <typename> typename Allocator = std::allocator>
class StackAllocator : public Allocator<T>
{
public:
using base = Allocator<T>;
using pointer_type = typename base::pointer;
using size_type = typename base::size_type;
StackAllocator() noexcept = default;
StackAllocator(const StackAllocator& a_StackAllocator) noexcept = default;
template <typename U>
StackAllocator(const StackAllocator<U, N, Allocator>& a_StackAllocator) noexcept
{
}
pointer_type allocate(size_type a_Size, void* a_Hint = nullptr)
{
if (!m_Active && a_Size <= N)
{
m_Active = true;
return GetStackPointer();
}
else
{
return base::allocate(a_Size, a_Hint);
}
}
void deallocate(pointer_type a_Pointer, size_type a_Size)
{
if (a_Pointer == GetStackPointer())
{
m_Active = false;
}
else
{
base::deallocate(a_Pointer, a_Size);
}
}
template <class U>
struct rebind
{
using other = StackAllocator<U, N, Allocator>;
};
private:
pointer_type GetStackPointer()
{
return reinterpret_cast<pointer_type>(m_Data);
}
std::aligned_storage_t<sizeof(T), alignof(T)> m_Data[N];
bool m_Active = false;
};
template <typename T, size_t N>
class StackVector : public std::vector<T, StackAllocator<T, N>>
{
public:
using allocator_type = StackAllocator<T, N>;
using base = std::vector<T, allocator_type>;
StackVector() noexcept(noexcept(allocator_type())):
StackVector(allocator_type())
{
}
explicit StackVector(const allocator_type& a_Allocator) noexcept(noexcept(base(a_Allocator))):
base(a_Allocator)
{
base::reserve(N);
}
using base::vector;
};
int main(int argc, char* argv[])
{
StackVector<size_t, 1> v;
return v.capacity();
}
我正在使用MSVC 2017(15.4.0)。
該標準要求從分配器'a'構造的分配器'b'拷貝 - 等於'a';這又意味着'a'分配的內存可以被'b'解除分配。你的班級違反了這個要求,因此不是一個有效的分配器。實際上,你繼承了'std :: allocator :: operator ==',它總是返回'true';但是你的班級實例是非常不可互換的。 –
原來的答案是downvoted,但主要的一點是你不能在分配器中存儲,因爲它們是無狀態的類價值類型。我什至不知道你會如何支持相同類型的多個這樣的分配器。另外,您必須努力確保分配仍在使用中時存儲不會超出範圍。例如。在存儲被破壞之前調用斷言釋放。 –