【发布时间】:2019-01-04 09:42:43
【问题描述】:
我创建了一个自定义分配器,它在构造时分配内存并在销毁时释放它。 (为了允许快速分配/解除分配)。 当我将它与 STL 容器一起使用时,一切正常!当我使用assign方法时预期... 我不明白为什么...
我尝试打印每个分配/空闲的指针,但一切看起来都不错。
#include <cstddef>
#include <type_traits>
#include <stack>
#include <numeric>
#include <list>
template <class T>
class CustomAllocator
{
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using propagate_on_container_copy_assignment = std::false_type;
using propagate_on_container_move_assignment = std::false_type;
using propagate_on_container_swap = std::false_type;
using is_always_equal = std::false_type;
CustomAllocator();
CustomAllocator(size_type size);
~CustomAllocator();
CustomAllocator(const CustomAllocator&);
CustomAllocator& operator=(const CustomAllocator&) = delete;
CustomAllocator(CustomAllocator&& src)
: m_data(std::move(src.m_data)) , m_free(std::move(src.m_free))
{
src.m_data = nullptr;
}
CustomAllocator& operator=(CustomAllocator&&) = delete;
template <class T2>
CustomAllocator(const CustomAllocator<T2>&);
template <class T2>
bool operator==(const CustomAllocator<T2>&) const noexcept;
template <class T2>
bool operator!=(const CustomAllocator<T2>&) const noexcept;
value_type* allocate(size_type);
void deallocate(value_type* ptr, size_type);
private:
template <class>
friend class CustomAllocator;
void* m_data = nullptr;
std::stack<void*> m_free;
};
template <class T>
CustomAllocator<T>::CustomAllocator() : CustomAllocator(1024)
{
}
template <class T>
CustomAllocator<T>::CustomAllocator(size_type size)
{
m_data = ::operator new(sizeof(T) * size);
for (auto ptr = static_cast<T*>(m_data) + (size - 1); ptr >=
static_cast<T*>(m_data); ptr--)
m_free.push(ptr);
}
template <class T>
CustomAllocator<T>::CustomAllocator(const CustomAllocator&)
: CustomAllocator(1024)
{
}
template <class T>
template <class T2>
CustomAllocator<T>::CustomAllocator(const CustomAllocator<T2>&)
: CustomAllocator(1024)
{
}
template <class T>
CustomAllocator<T>::~CustomAllocator()
{
if (m_data)
::operator delete(m_data);
}
template <class T>
template <class T2>
inline bool CustomAllocator<T>::
operator==(const CustomAllocator<T2>&) const noexcept
{
return typeid(T) == typeid(T2);
}
template <class T>
template <class T2>
inline bool CustomAllocator<T>::
operator!=(const CustomAllocator<T2>&) const noexcept
{
return typeid(T) != typeid(T2);
}
template <class T>
typename CustomAllocator<T>::value_type*
CustomAllocator<T>::allocate(size_type size)
{
if (m_free.empty() || size != 1)
throw std::bad_alloc();
auto ptr = m_free.top();
m_free.pop();
return reinterpret_cast<value_type*>(ptr);
}
template <class T>
void CustomAllocator<T>::deallocate(value_type* ptr, size_type)
{
m_free.push(ptr);
}
int main()
{
std::list<size_t, CustomAllocator<size_t>> containerA;
std::list<size_t, CustomAllocator<size_t>> containerB;
for (size_t i = 0; i < 10; ++i)
{
for (size_t j = 0; j < 100; ++j)
containerA.emplace_front();
// dont works with this
containerB.assign(10, i);
containerA.clear();
containerB.clear();
}
return 0;
}
实际上程序崩溃了。 如果我评论 'containerB.assign(10, i);',程序就可以工作。 如果我替换 'containerB.assign(10, i);'通过 'containerB.emplace_front();',程序运行。 如果我替换 'containerB.assign(10, i);'通过 'containerB.insert(containerB.begin(), 10, i);',程序崩溃。 我不明白为什么...
clang 和 gcc 错误: free():损坏的未排序块 中止(核心转储)
gdb 错误: free(): 损坏的未排序块
程序收到信号 SIGABRT,已中止。 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51 51 ../sysdeps/unix/sysv/linux/raise.c:没有这样的文件或目录。
更新:
有了更好的运算符 ==,我现在有了一个 SIGSEGV: 程序收到信号 SIGSEGV,分段错误。 /usr/include/c++/8/bits/list.tcc:74 的 std::__cxx11::_List_base >::_M_clear (this=0x7fffffffdcd0) 中的 0x000055555555537a 74 __cur = __tmp->_M_next;
valgrind 输出:
==17407== Memcheck, a memory error detector
==17407== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==17407== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==17407== Command: ./a.out
==17407==
==17407== Invalid read of size 8
==17407== at 0x10937A: std::__cxx11::_List_base<unsigned long, CustomAllocator<unsigned long> >::_M_clear() (list.tcc:74)
==17407== by 0x109287: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::clear() (stl_list.h:1507)
==17407== by 0x108F0C: main (bug.cpp:154)
==17407== Address 0x5b93b00 is 0 bytes inside a block of size 24,576 free'd
==17407== at 0x4C3123B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17407== by 0x1091CE: CustomAllocator<std::_List_node<unsigned long> >::~CustomAllocator() (bug.cpp:100)
==17407== by 0x109107: std::__cxx11::_List_base<unsigned long, CustomAllocator<unsigned long> >::_List_impl::~_List_impl() (stl_list.h:382)
==17407== by 0x109205: std::__cxx11::_List_base<unsigned long, CustomAllocator<unsigned long> >::~_List_base() (stl_list.h:506)
==17407== by 0x10915B: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::~list() (stl_list.h:834)
==17407== by 0x109B66: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::insert(std::_List_const_iterator<unsigned long>, unsigned long, unsigned long const&) (list.tcc:122)
==17407== by 0x109586: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::_M_fill_assign(unsigned long, unsigned long const&) (list.tcc:300)
==17407== by 0x10926C: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::assign(unsigned long, unsigned long const&) (stl_list.h:897)
==17407== by 0x108EEE: main (bug.cpp:151)
==17407== Block was alloc'd at
==17407== at 0x4C3017F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17407== by 0x109665: CustomAllocator<std::_List_node<unsigned long> >::CustomAllocator(unsigned long) (bug.cpp:76)
==17407== by 0x10A3B6: CustomAllocator<std::_List_node<unsigned long> >::CustomAllocator<unsigned long>(CustomAllocator<unsigned long> const&) (bug.cpp:92)
==17407== by 0x109FFE: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::list(unsigned long, unsigned long const&, CustomAllocator<unsigned long> const&) (stl_list.h:717)
==17407== by 0x109B0B: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::insert(std::_List_const_iterator<unsigned long>, unsigned long, unsigned long const&) (list.tcc:122)
==17407== by 0x109586: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::_M_fill_assign(unsigned long, unsigned long const&) (list.tcc:300)
==17407== by 0x10926C: std::__cxx11::list<unsigned long, CustomAllocator<unsigned long> >::assign(unsigned long, unsigned long const&) (stl_list.h:897)
==17407== by 0x108EEE: main (bug.cpp:151)
==17407==
==17407==
==17407== HEAP SUMMARY:
==17407== in use at exit: 0 bytes in 0 blocks
==17407== total heap usage: 504 allocs, 504 frees, 668,800 bytes allocated
==17407==
==17407== All heap blocks were freed -- no leaks are possible
==17407==
==17407== For counts of detected and suppressed errors, rerun with: -v
==17407== ERROR SUMMARY: 100 errors from 1 contexts (suppressed: 0 from 0)
【问题讨论】:
-
崩溃?抛出异常?
-
仅供参考,
voidforT在您的size_t参数构造函数中会导致最好的行为。同样的问题也发生在其他地方。坦率地说,我很震惊你的编译器没有像我的那样向你发出警告(应该被视为错误)。 -
我已将 for 替换为:for (auto ptr = static_cast
(m_data) + (size - 1); ptr >= static_cast (m_data); ptr- -) m_free.push(ptr);但不工作。 -
程序崩溃:SIGABRT
-
您是否尝试过调试,例如查看您的 allocate 和 deallocate 函数是如何实际调用的?还是在 valgrind 之类的工具下运行?