带有 STL 向量的自定义分配器(在 Visual Studio 工具链中)

Custom allocator with a STL vector (within Visual Studio toolchain)

将自定义分配器与 STL 向量(在 Visual Studio 工具链中)一起使用时,构造函数被调用 3 次,析构函数被调用 4 次。我错过了什么?以下是代码及其输出:

#include <iostream>
#include <stdlib.h>
#include <new>
#include <memory> 
#include <vector>

using namespace std;

template <class T>
struct Mallocator
{
    typedef T value_type;
    Mallocator() noexcept { cout << "Mallocator() " << this << endl; }
    ~Mallocator() noexcept { cout << "~Mallocator() " << this << endl; }

    template<class U> Mallocator(const Mallocator<U>&) noexcept { cout << "Mallocator(const Mallocator<U>&) " << this << endl; }
    template<class U> Mallocator(Mallocator<U>&&) noexcept { cout << "Mallocator(Mallocator<U>&&) " << this << endl; }

    template<class U> bool operator==(const Mallocator<U>&) const noexcept
    {
        return true;
    }
    template<class U> bool operator!=(const Mallocator<U>&) const noexcept
    {
        return false;
    }
    T* allocate(const size_t n) const;
    void deallocate(T* const p, size_t) const noexcept;
};

template <class T>
T* Mallocator<T>::allocate(const size_t n) const
{
    cout << "   allocate from" << this << endl;
    if (n == 0)
    {
        return nullptr;
    }
    if (n > static_cast<size_t>(-1) / sizeof(T))
    {
        throw std::bad_array_new_length();
    }
    void* const pv = malloc(n * sizeof(T));
    if (!pv) { throw std::bad_alloc(); }
    return static_cast<T*>(pv);
}

template<class T>
void Mallocator<T>::deallocate(T * const p, size_t) const noexcept
{
    cout << "   deallocate from" << this << endl;
    free(p);
}

int main()
{
    Mallocator<uint8_t> mall{};
    std::vector<uint8_t, Mallocator<uint8_t>> v(mall);
    return 0;
}

输出如下:

Mallocator() 0058FDF3
Mallocator(const Mallocator<U>&) 0058FADF
        allocate from0058FADF
~Mallocator() 0058FADF
Mallocator(const Mallocator<U>&) 0058FAF3
        deallocate from0058FAF3
~Mallocator() 0058FAF3
~Mallocator() 0058FDD8
~Mallocator() 0058FDF3

此外,即使不使用向量,分配器也已经被实例化了 3 次(或者可能是 4 次,因为析构函数被调用了 4 次),这与仅实例化它一次的 GCC 工具链相比要多得多。

我已将复制和移动构造函数添加到您在 template <class T> struct Mallocator

中的代码中
Mallocator(const Mallocator&) { cout << "Mallocator&() " << this << endl; }  
Mallocator(const Mallocator&&) { cout << "Mallocator&&() " << this << endl; } 

这是我使用 GCC 7.1.0 得到的输出:

Mallocator() 0x61fe3f
Mallocator&() 0x61fe20
~Mallocator() 0x61fe20
~Mallocator() 0x61fe3f

本次调用构造函数和析构函数的次数匹配。您也可以在 Visual Studio 工具链中对此进行测试。