Code below runs fine when compiled with VC compiler, but fail with abort
inside list.sort
on Linux when compiled with gcc (any recent version like 7.5 to 10.2).
The reason why abort is called is because splice
method used in list.sort
compares 2 allocators (which is correct) and they don't match. One of them is what I pass into list
constructor (with custom state), another is created by STL using default constructor.
My question - is this correct behavior of C++ library to use allocator's default constructor as opposed to using instance which I provide for item allocation or create it with copying constructor?
UPDATE: As T.C. mentioned in comment this is known libstdc++ bug 66742.
#include <iostream>
#include <list>
#include <cassert>
using namespace std;
template <typename T>
class my_allocator
{
public:
using value_type = typename std::remove_const<T>::type;
using pointer = value_type*;
using size_type = size_t;
typedef std::true_type propagate_on_container_copy_assignment;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type propagate_on_container_swap;
template<typename U>
struct rebind {
typedef my_allocator<U> other;
};
my_allocator() : m_internalState(0)
{
cout << "my_allocator(): internal state=" << m_internalState << endl;
}
my_allocator(const void* pAllocator) : m_internalState(pAllocator)
{
cout << "my_allocator(const void * pAllocator): internal state=" << m_internalState << endl;
}
template <typename U>
my_allocator(const my_allocator<U>& myAllocator) noexcept : m_internalState(myAllocator.m_internalState)
{
cout << "my_allocator(const my_allocator<U>& myAllocator): internal state=" << m_internalState << endl;
}
pointer allocate(size_type count, const void* = nullptr)
{
return (pointer)malloc(sizeof(T) * count);
}
void deallocate(pointer p, size_type count = 0)
{
free(p);
}
bool operator==(const my_allocator& other) const
{
cout << "operator==(const my_allocator& other): this=" << m_internalState
<< ", other=" << other.m_internalState << endl;
return m_internalState == other.m_internalState;
}
bool operator!=(const my_allocator& other) const
{
return !(this->operator==(other));
}
private:
template <typename U>
friend class my_allocator;
const void* m_internalState;
};
int main()
{
// all asserts below are true
//using X = my_allocator<int>;
//using Y = my_allocator<long>;
//Y b((void*)1);
//X a(b);
//assert(Y(a) == b);
//assert(a == X(b));
//assert(a == b);
cout << "Create list" << endl;
auto allocator = my_allocator<int>((void*)2);
auto l2 = std::list<int, my_allocator<int>>(allocator);
l2.emplace_back(2);
l2.emplace_back(1);
cout << "Sort list" << endl;
l2.sort(); // Abort is called here
cout << "Success" << endl;
return 0;
}
C++ (vc++) output (as provided by running this code on https://rextester.com/l/cpp_online_compiler_visual
Create list
my_allocator(const void * pAllocator): internal state=0000000000000002
my_allocator(const my_allocator<U>& myAllocator): internal state=0000000000000002
Sort list
operator==(const my_allocator& other): this=0000000000000002, other=0000000000000002
Success
C++ (gcc) output
Error(s):
Abort signal from abort(3) (SIGABRT)
Create list
my_allocator(const void * pAllocator): internal state=0x2
my_allocator(const my_allocator<U>& myAllocator): internal state=0x2
Sort list
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
my_allocator(): internal state=0
operator==(const my_allocator& other): this=0, other=0x2
Stack trace when abort
is called
> std::__cxx11::list<int, my_allocator<int> >::_M_check_equal_allocators(std::__cxx11::list<int, my_allocator<int> > * const this, std::__cxx11::list<int, my_allocator<int> > & __x) Line 1829
std::__cxx11::list<int, my_allocator<int> >::splice(std::__cxx11::list<int, my_allocator<int> > * const this, std::__cxx11::list<int, my_allocator<int> >::const_iterator __position, std::__cxx11::list<int, my_allocator<int> > & __x, std::__cxx11::list<int, my_allocator<int> >::const_iterator __i) Line 1480
std::__cxx11::list<int, my_allocator<int> >::splice(std::__cxx11::list<int, my_allocator<int> > * const this, std::__cxx11::list<int, my_allocator<int> >::const_iterator __position, std::__cxx11::list<int, my_allocator<int> > & __x, std::__cxx11::list<int, my_allocator<int> >::const_iterator __i) Line 1502
std::__cxx11::list<int, my_allocator<int> >::sort(std::__cxx11::list<int, my_allocator<int> > * const this) Line 481
main() Line 90
Aucun commentaire:
Enregistrer un commentaire