#include <iostream>
#include <set>
#include <string>
#include <type_traits>

template <typename T>
struct NoisyAlloc
{
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;

    using value_type = T;
    using pointer = T *;
    using const_pointer = const T *;
    using reference = T &;
    using const_reference = const T &;

    template <typename U> struct rebind { using other = NoisyAlloc<U>; };

    T * allocate(std::size_t n)
    {
        std::cout << "Allocating " << n << " units.\n";
        return static_cast<T *>(::operator new(n * sizeof(T)));
    }
    void deallocate(T * p, std::size_t n)
    {
        std::cout << "Freeing " << n << " units.\n";
        ::operator delete(p);
    }

    using is_always_equal = std::true_type;
    bool operator==(const NoisyAlloc&) const { return true; }
    bool operator!=(const NoisyAlloc&) const { return false; }
};


int main()
{
    std::set<unsigned char> s;
    for (unsigned int c = 0; c < 0x100; ++c) s.insert(c);

    std::basic_string<char, std::char_traits<char>, NoisyAlloc<char>> str(s.begin(), s.end());
    
    //std::basic_string<char, std::char_traits<char>, NoisyAlloc<char>> str;
    //str.reserve(500);
    //str.append(s.begin(), s.end());
    //str.assign(s.begin(), s.end());
    //str.insert(str.end(), s.begin(), s.end());
    //for (unsigned char c : s) str.push_back(c);
}