【问题标题】:Custom allocator method is not called不调用自定义分配器方法
【发布时间】:2020-07-02 06:15:24
【问题描述】:

我正在尝试学习和编写一个自定义分配器 - 我期待应该打印 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

【问题讨论】:

    标签: c++ c++11 visual-c++ c++14


    【解决方案1】:

    不需要继承标准分配器。删除继承: public std::allocator&lt;T&gt;,编译器会很乐意通知您您错过了哪些实现。在 C++17 之前,必须实现方法 construct,并且它用于 std::vector,而不是 allocate。还缺少value_typedeallocatordestroy

    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. 标准容器不直接使用class Allocator。他们使用std::allocator_traits。它有助于实现最少的用户定义分配器。如果只实现MyAllocatorvalue_typeallocatedeallocate 成员,std::allocator_traits&lt;MyAllocator&gt; 使MyAllocator 完全符合C++ named requirements: 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 将被调用。

    【讨论】:

    • 我如前所述进行了更改,并在我的类中添加了构造方法,只是在那里打印了一条语句以查看代码流是否出现但仍然是相同的输出 - 我没有看到执行我的任何分配器的代码方法被调用
    • 不可能。请编辑您的问题并显示您的更新。
    • 感谢您的示例 - 请告诉我为什么继承 : public std::allocator 不是必需的或代码失败?
    • 我已经扩展了答案。
    【解决方案2】:

    你已经成功了一半。如here 所述,该标准描述了具有几个可选和必需的命名属性和方法的自定义分配器类。如果您希望您的示例正常工作,至少您必须实现所需的示例。它们是:

    • 添加value_type
    • 添加allocate(n) 方法。接受 size_t 输入并返回地址。
    • 添加deallocate(p, n) 方法。接受两个输入,没有输出。

    您还必须删除对std::allocator 的继承(请参阅@S.M. 的回答)。类似于您的 MyAllocator 类的示例:

    #include <iostream>
    #include <vector>
    #include <cstdlib>
    
    template < class T >
    class MyAllocator
    {
    public:
        T * allocate(size_t size)
        {
            std::cout << "Allocation request size => " << size << std::endl;
            return new T[size];
        }
        void deallocate(T * p_t, size_t n)
        {
            std::free(p_t);
        }
        using value_type = T;
    };
    
    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;
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-26
      相关资源
      最近更新 更多