Пользовательский метод распределителя не вызывается - PullRequest
2 голосов
/ 21 марта 2020

Я пытаюсь выучить и написать собственный пользовательский распределитель - я ожидал, что оператор cout должен быть напечатан, но он никогда не делает - что я делаю неправильно - как написать собственный распределитель:

#include <iostream>
#include <vector>

template < class T >
class MyAllocator : public std::allocator<T> {
public:
    T* allocate(size_t size)
    {
        std::cout << "Allocation request size " << size << std::endl;
        return new T[size];
    }

};

int main()
{
    std::vector <int, MyAllocator<int>> x;
    x.push_back(10);
    x.push_back(10);
    x.push_back(10);

    for (auto& var : x)
        std::cout << "Value " << var << std::endl;

}

Выход

Value 10
Value 10
Value 10

1 Ответ

1 голос
/ 21 марта 2020

Наследование стандартного распределителя не требуется. Удалите наследство : public std::allocator<T>, и компилятор будет любезен сообщить вам о том, что вы пропустили для реализации. До C ++ 17 метод construct должен быть реализован, и он используется в std::vector, а не allocate. Также отсутствуют value_type, deallocator и destroy.

template< class U, class... Args >
void construct( U* p, Args&&... args );

Так как вы не реализовали это, и ваш распределитель наследует стандартный распределитель, вызывается std::allocator::construct, который не производит вывод ,

Почему вы не должны наследовать std :: allocator

Ответ на этот вопрос прост, с одной стороны, и непрост на практике, с другой стороны.

  1. Как и другие классы в стандартной библиотеке C ++, std::allocator не имеет виртуального деструктора, поэтому он не должен наследоваться, если он не указан явно, как в std::enable_shared_from_this.
  2. Стандартные контейнеры don не использовать class Allocator напрямую. Они используют std::allocator_traits. Это помогает реализовать минимальные пользовательские распределители. Если вы реализуете только value_type, allocate и deallocate членов MyAllocator, std::allocator_traits<MyAllocator> делает MyAllocator полностью соответствующим C ++ названным требованиям: Allocator .

    • Давайте внимательно посмотрим на ваш MyAllocator. Он наследует std::allocator и «заменяет» std::allocator::allocate (2).
    • Позволяет прочитать std::allocator_traits::allocate (2) справочное руководство, которое вызывается std::vector:

      Звонит a.allocate(n, hint), если это возможно. Если невозможно (например, a не имеет функции-члена allocate () с двумя аргументами), вызывает a.allocate(n).

    То, что вы достигли. Вы реализовали MyAllocator::allocate(std::size_t n) (2), но не MyAllocator::allocate(std::size_t n, const void* hint) (1), он унаследован от std::allocator. Он вызывается с std::vector, это не то, что вы ожидали. Если бы вы не унаследовали std::allocator, была бы вызвана ваша реализация MyAllocator::allocate.

...