Пользовательский освободитель с std :: vector не вызывается

Я ожидаю, что этот код напечатает «Hello world» - «Hello», когда память освобождена, и «world» в main. Однако «Hello» никогда не печатается, а это означает, что мой деаллокатор не вызывается. Как правильно это реализовать?

#include <iostream>
#include <vector>

class MyAllocator : public std::allocator<uint8_t>
{
public:
  void deallocate(uint8_t* data, std::size_t size)
  {
    std::cout << "Hello ";
    std::allocator<uint8_t>::deallocate(data, size);
  }
};


int main()
{
  {
    std::vector<uint8_t, MyAllocator> v(100);
  }
  std::cout << "world\n";

  return 0;
}

Я предполагаю, что он просто вызывает функцию по умолчанию std::allocator<uint8_t>::deallocate(), но я не вижу способа предотвратить это и заставить ее вызывать мою функцию.


person Valentin    schedule 02.03.2018    source источник
comment
Старайтесь не говорить, что это не работает, это не значимая диагностика. Я изменил заголовок, чтобы лучше отразить ваш вопрос.   -  person tadman    schedule 02.03.2018
comment
Я думаю, что создание настраиваемого распределителя немного сложнее, т.е. stackoverflow.com/questions/21081796/   -  person Robinson    schedule 02.03.2018
comment
Я действительно не вижу концептуальной разницы между их распределителем и моим. Конечно, у них есть шаблоны и еще пара конструкторов, но если std :: vector нужно вызвать что-то, чего не хватает моему классу, он не будет компилироваться. Что мне не хватает?   -  person Valentin    schedule 02.03.2018


Ответы (2)


Фактически ваш распределитель будет работать, если вы определите rebind:

#include <iostream>
#include <vector>

class MyAllocator : public std::allocator<uint8_t>
{
public:

    template <typename U>
    struct rebind
    {
        typedef MyAllocator other;
    };

    void deallocate(uint8_t* data, std::size_t size)
    {
        std::cout << "Hello ";
        std::allocator<uint8_t>::deallocate(data, size);
    }
};


int main()
{
  {
    std::vector<uint8_t, MyAllocator> v(100);
  }
  std::cout << "world\n";

  return 0;
}

Производит:

Привет, мир

person Robinson    schedule 02.03.2018
comment
Работает для gcc, но в VS выдает ошибку: Error C2664 'void std::_Deallocate_plain<MyAllocator,0>(_Alloc &,unsigned char *const )': cannot convert argument 2 from 'std::_Container_proxy *' to 'unsigned char *const ' HelloTest c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.12.25827\include\vector 557 - person Valentin; 02.03.2018
comment
Он отлично компилируется со стандартом VS 2017 / ISO C ++ 17. (\std::c++17) - person Jive Dadson; 02.03.2018

std::allocator определяет член template rebind<U>.

И std::vector правильно использует его, чтобы убедиться, что он выделяет правильные фрагменты памяти с соответствующим размером и выравниванием, поэтому, даже если вы передали свой собственный распределитель, в результате повторной привязки фактически используется стандартный распределитель.

См., Например, http://en.cppreference.com/w/cpp/concept/Allocator для потенциальных участников распределителя.

person Deduplicator    schedule 02.03.2018