在C++20中如何编写一个自定义分配器以用于std::map

huangapple go评论62阅读模式
英文:

how to write a custom allocator for std::map in C++20

问题

I understand your request. Here's the translated portion of your text:

根据cppreference,我们需要为我们自己的自定义分配器定义rebind_alloc。但我并不真正了解如何使我的自定义分配器也对我的映射节点有效。

我所做的:

template <class T>
class Allocator2
{
public:
    using value_type = T;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t ;
    using propagate_on_container_move_assignment  = std::true_type;

    // 我不确定在这里需要什么rebind_alloc... ???
    template<typename U>
    using rebind_alloc = typename std::allocator_traits<Allocator2<T>>::template rebind_alloc<U>;

    T* allocate(size_type n, const void* hint = 0)
    {
        std::cout << "Alloc" << n << std::endl;
        return static_cast<T*>(malloc(n * sizeof(T)));
    }

    void deallocate(T* p, size_type n) { free(p); }
    size_type max_size() const { return size_type(std::numeric_limits<unsigned int>::max() / sizeof(T)); }
    void construct(T* p, const T& value) { _construct(p, value); }
    void destroy(T* p) { _destroy(p); }
};

template<class T, class U>
bool operator==(const Allocator2 <T>&, const Allocator2 <U>&) noexcept { return true; }

template<class T, class U>
bool operator!=(const Allocator2 <T>&, const Allocator2 <U>&) noexcept { return false; }

struct PointCmp {
    bool operator()(const int& lhs, const int& rhs) const
    {   
        return lhs == rhs;
    }
};

template <typename T>
void Print(T t)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

int main()
{
    using valueType = std::map<int, int>::value_type;
    Print(valueType{});
    std::map<int, int, PointCmp, Allocator2<valueType>> m;

    for (unsigned int n = 0; n < 1000; n++)
    {
        std::cout << "Now set " << n << std::endl;
        m[n] = n;
    }
}

请问有人能指出要为rebind_alloc设置什么吗?
也许还有一个提示,除了看到为我的映射类型分配的节点外,还缺少什么?

(Note: The code snippet you provided contains HTML encoding for characters like "<" and "&," which I have left as-is in the translation.)

英文:

As I understand from cppreference we need to define rebind_alloc for our own custom allocator. But I did not really understand how I can let my own allocator also valid for the nodes of my map.

What I did:

template &lt;class T&gt;
class Allocator2
{
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t ;
using propagate_on_container_move_assignment  = std::true_type;
// no idea what I need for rebind_alloc here... ???
template&lt;typename U&gt;
using rebind_alloc = typename std::allocator_traits&lt;Allocator2&lt;T&gt;&gt;::template rebind_alloc&lt;U&gt;;
T* allocate(size_type n, const void* hint = 0)
{
std::cout &lt;&lt; &quot;Alloc&quot; &lt;&lt; n &lt;&lt; std::endl;
return static_cast&lt;T*&gt;(malloc(n*sizeof(T)));
}
void deallocate(T* p, size_type n) { free( p); }
size_type max_size() const { return size_type(std::numeric_limits&lt;unsigned int&gt;::max() / sizeof(T)); }
void construct(T* p, const T&amp; value) { _construct(p, value); }
void destroy(T* p) { _destroy(p); }
};
template&lt;class T, class U&gt;
bool operator==(const Allocator2 &lt;T&gt;&amp;, const Allocator2 &lt;U&gt;&amp;) noexcept { return true; }
template&lt;class T, class U&gt;
bool operator!=(const Allocator2 &lt;T&gt;&amp;, const Allocator2 &lt;U&gt;&amp;) noexcept { return false; }
struct PointCmp {
bool operator()(const int&amp; lhs, const int&amp; rhs ) const
{   
return lhs==rhs;
}
};
template &lt; typename T&gt;
void Print( T t)
{
std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; std::endl;
}
int main()
{
using valueType = std::map&lt; int, int&gt;::value_type;
Print( valueType{} );
std::map&lt; int, int , PointCmp, Allocator2&lt; valueType&gt;&gt; m;
for ( unsigned int n = 0; n&lt;1000; n++ )
{
std::cout &lt;&lt; &quot;Now set &quot; &lt;&lt; n &lt;&lt; std::endl;
m[n]=n;
}
}

Can someone point out what to set for rebind_alloc?
Maybe also a hint what is missing in addition to see nodes allocated for my map type?

答案1

得分: 1

Here is the translation of the code portion you provided:

如何编写自定义分配器?

你已经完成了这个任务。

正如其他人在评论中指出的,对于你的分配器,不需要使用 `rebind_alloc`。

然而,你的比较器是有问题的。因为 map 通过 `!comp(a,b) && !comp(b,a)` 来检查等价性,所以对于你的比较器来说,除非它们相等,否则任何两个元素都被认为是等价的。这是不正确的。也许这就是你得出你的分配器有问题的结论的原因。尽管当所有数字都等价时,只插入第一个数字而不是其他数字是正确的。

请注意,当你可以使用 `std::less<>` 时,没有必要定义自定义比较器。

修复这个问题并添加包含文件后,你的分配器将按预期工作:

#include <type_traits>
#include <memory>
#include <iostream>
#include <limits>
#include <map>

template <class T>
class Allocator2
{
    public:
        using value_type = T;
        using size_type = std::size_t;
        using difference_type = std::ptrdiff_t ;
        using propagate_on_container_move_assignment  = std::true_type;

       
        T* allocate(size_type n, const void* hint = 0)
        {
            std::cout << "Alloc" << n << std::endl;
            return static_cast<T*>(malloc(n * sizeof(T)));
        }

        void deallocate(T* p, size_type n) { free(p); }
        size_type max_size() const { return size_type(std::numeric_limits<unsigned int>::max() / sizeof(T)); }
        void construct(T* p, const T& value) { _construct(p, value); }
        void destroy(T* p) { _destroy(p); }
};

template<class T, class U>
bool operator==(const Allocator2 <T>&, const Allocator2 <U>&) noexcept { return true; }

template<class T, class U>
bool operator!=(const Allocator2 <T>&, const Allocator2 <U>&) noexcept { return false; }

struct PointCmp {
    bool operator()(const int& lhs, const int& rhs ) const
    {   
        return lhs < rhs;
    }
};

template <typename T>
void Print( T t)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

int main()
{
    using valueType = std::map< int, int>::value_type;
    Print( valueType{} );
    std::map< int, int , std::less<>, Allocator2< valueType>> m;

    for ( unsigned int n = 0; n<10; n++ )
    {
        std::cout << "Now set " << n << std::endl;
        m[n]=n;
    }
}

Live Demo


Please note that I've made the necessary code translations, and you can use this code as needed.
<details>
<summary>英文:</summary>
&gt; how to write a custom allocator ?
You just did that. 
As others pointed out in comments `rebind_alloc` is not needed for your allocator. 
Your comparator is broken however. As the map checks for equivalence via `! comp(a,b) &amp;&amp; ! comp(b,a)`, with your comparator, any two element are considered equivalent unless they are equal. Thats not right. Perhaps thats why you concluded there would be something wrong with your allocator. Though, when all numbers are equivalent, it is correct to insert only the first and not the others. 
Note that there is no need to define a custom comparator when you can use `std::less&lt;&gt;`. 
Fixing that and adding the includes your allocater works as expected:
#include &lt;type_traits&gt;
#include &lt;memory&gt;
#include &lt;iostream&gt;
#include &lt;limits&gt;
#include &lt;map&gt;
template &lt;class T&gt;
class Allocator2
{
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t ;
using propagate_on_container_move_assignment  = std::true_type;
T* allocate(size_type n, const void* hint = 0)
{
std::cout &lt;&lt; &quot;Alloc&quot; &lt;&lt; n &lt;&lt; std::endl;
return static_cast&lt;T*&gt;(malloc(n*sizeof(T)));
}
void deallocate(T* p, size_type n) { free( p); }
size_type max_size() const { return size_type(std::numeric_limits&lt;unsigned int&gt;::max() / sizeof(T)); }
void construct(T* p, const T&amp; value) { _construct(p, value); }
void destroy(T* p) { _destroy(p); }
};
template&lt;class T, class U&gt;
bool operator==(const Allocator2 &lt;T&gt;&amp;, const Allocator2 &lt;U&gt;&amp;) noexcept { return true; }
template&lt;class T, class U&gt;
bool operator!=(const Allocator2 &lt;T&gt;&amp;, const Allocator2 &lt;U&gt;&amp;) noexcept { return false; }
struct PointCmp {
bool operator()(const int&amp; lhs, const int&amp; rhs ) const
{   
return lhs &lt; rhs;
}
};
template &lt; typename T&gt;
void Print( T t)
{
std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; std::endl;
}
int main()
{
using valueType = std::map&lt; int, int&gt;::value_type;
Print( valueType{} );
std::map&lt; int, int , std::less&lt;&gt;, Allocator2&lt; valueType&gt;&gt; m;
for ( unsigned int n = 0; n&lt;10; n++ )
{
std::cout &lt;&lt; &quot;Now set &quot; &lt;&lt; n &lt;&lt; std::endl;
m[n]=n;
}
}
[Live Demo](https://godbolt.org/z/5K6ebs4vd)
</details>

huangapple
  • 本文由 发表于 2023年6月21日 23:47:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76525067.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定