std::string с настраиваемым распределителем

Итак, в настоящее время я пишу отладчик памяти, и для этого мне нужны объекты контейнера stl для использования неотслеживаемого распределителя.

У меня есть std::string, приправленный всей моей кодовой базой, поэтому я набрал его, чтобы использовать свой неотслеживаемый распределитель:

typedef std::basic_string<char, std::char_traits<char>, UntrackedAllocator<char>> String;

Теперь, когда я пытаюсь сделать это:

String str { "Some string" };
String copy = str;

Я получаю эту ошибку:

/usr/local/include/c++/7.1.0/ext/alloc_traits.h:95:67: error: no matching function for call to 'UntrackedAllocator<char>::UntrackedAllocator(UntrackedAllocator<char>)' { return _Base_type::select_on_container_copy_construction(__a); }

Вот как выглядит мой Untracked Allocator:

#pragma once

#define NOMINMAX
#undef max

template <typename T>
class UntrackedAllocator {
public:
    typedef T value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;

public:
    template<typename U>
    struct rebind {
        typedef UntrackedAllocator<U> other;
    };

public:
    inline explicit UntrackedAllocator() {}
    inline ~UntrackedAllocator() {}
    inline explicit UntrackedAllocator(UntrackedAllocator const&) {}
    template<typename U>
    inline explicit UntrackedAllocator(UntrackedAllocator<U> const&) {}

    //    address
    inline pointer address(reference r) {
        return &r;
    }

    inline const_pointer address(const_reference r) {
        return &r;
    }

    //    memory allocation
    inline pointer allocate(size_type cnt,
        typename std::allocator<void>::const_pointer = 0) {
        T *ptr = (T*)malloc(cnt * sizeof(T));
        return ptr;
    }

    inline void deallocate(pointer p, size_type cnt) {
        free(p);
    }

    //   size
    inline size_type max_size() const {
        return std::numeric_limits<size_type>::max() / sizeof(T);
    }

    // construction/destruction
    inline void construct(pointer p, const T& t) {
        new(p) T(t);
    }

    inline void destroy(pointer p) {
        p->~T();
    }

    inline bool operator==(UntrackedAllocator const& a) { return this == &a; }
    inline bool operator!=(UntrackedAllocator const& a) { return !operator==(a); }
};

Я впервые работаю с пользовательскими распределителями, поэтому понятия не имею, что с этим происходит. Невероятно раздражает, что я не могу сделать str1 = str2, если один из них использует собственный распределитель.


person Taylor Bishop    schedule 28.05.2016    source источник
comment
Ваши реляционные операторы неверны. Распределители должны сравниваться равными всякий раз, когда один может освободить выделение другого.   -  person Kerrek SB    schedule 28.05.2016
comment
stackoverflow.com/help/mcve   -  person Benjamin Lindley    schedule 28.05.2016
comment
Сообщение об ошибке подразумевает, что вы где-то используете конструктор копирования. В опубликованном вами коде не используется копия конструктора, если только ваш оператор индекса не возвращает значение. В любом случае явное создание конструктора копирования редко бывает полезным. Удалите explicit из конструктора копирования, и все должно быть в порядке.   -  person Dietmar Kühl    schedule 28.05.2016
comment
@KerrekSB Что ты имеешь в виду?   -  person Taylor Bishop    schedule 29.05.2016


Ответы (1)


Проблема заключается в объявлении копий c'tors как explicit.

Изменение UntrackedAllocator копии c'tor на:

inline UntrackedAllocator(UntrackedAllocator const&) {}

Решает проблему компиляции, и все работает нормально:

int main() {
  String str { "13" };
  String copy = str;
  const char* cstr = str.c_str();
  int out = atoi(cstr);
}

Это происходит потому, что оператор присваивания std::basic_string, который принимает const std::basic_string &, требует неявной конструкции копии распределителя.

person Daniel Trugman    schedule 16.10.2017