用户提供的std :: allocator专业化

问题描述 投票:1回答:1

::std名称空间中的类模板通常可以由程序专用于用户定义的类型。对于std::allocator,我没有发现此规则有任何例外。

所以,我可以专门为自己的类型专门研究std::allocator吗?并且如果允许的话,我是否需要提供std::allocator主模板的所有成员,因为其中许多可以由std::allocator_traits提供(因此在C ++ 17中已弃用)?

考虑this program

#include<vector>
#include<utility>
#include<type_traits>
#include<iostream>
#include<limits>
#include<stdexcept>

struct A { };

namespace std {
    template<>
    struct allocator<A> {
        using value_type = A;
        using size_type = std::size_t;
        using difference_type = std::ptrdiff_t;
        using propagate_on_container_move_assignment = std::true_type;

        allocator() = default;

        template<class U>
        allocator(const allocator<U>&) noexcept {}

        value_type* allocate(std::size_t n) {
            if(std::numeric_limits<std::size_t>::max()/sizeof(value_type) < n)
                throw std::bad_array_new_length{};
            std::cout << "Allocating for " << n << "\n";
            return static_cast<value_type*>(::operator new(n*sizeof(value_type)));
        }

        void deallocate(value_type* p, std::size_t) {
            ::operator delete(p);
        }

        template<class U, class... Args>
        void construct(U* p, Args&&... args) {
            std::cout << "Constructing one\n";
            ::new((void *)p) U(std::forward<Args>(args)...);
        };

        template<class U>
        void destroy( U* p ) {
            p->~U();
        }

        size_type max_size() const noexcept {
            return std::numeric_limits<size_type>::max()/sizeof(value_type);
        }
    };
}

int main() {
    std::vector<A> v(2);
    for(int i=0; i<6; i++) {
        v.emplace_back();
    }
    std::cout << v.size();
}

使用libc ++(带有-std=c++17 -Wall -Wextra -pedantic-errors -O2 -stdlib=libc++的Clang的程序)的输出是:

Allocating for 2
Constructing one
Constructing one
Allocating for 4
Constructing one
Constructing one
Allocating for 8
Constructing one
Constructing one
Constructing one
Constructing one
8

并且libstdc ++(带有-std=c++17 -Wall -Wextra -pedantic-errors -O2 -stdlib=libstdc++的Clang)的输出是:

Allocating for 2
Allocating for 4
Constructing one
Constructing one
Allocating for 8
Constructing one
Constructing one
Constructing one
Constructing one
8

[您可以看到libstdc ++并不总是尊重我提供的construct的重载,如果我删除了constructdestroymax_size成员,则该程序甚至不会编译并带有libstdc ++的抱怨关于这些丢失的成员,尽管它们由std::allocator_traits提供。

程序是否具有未定义的行为,因此都是标准库,还是正确定义了程序的行为以及使用我的专业化所需的标准库?


[请注意,std::allocator的主要模板中有一些成员在我的专业化工作中仍然遗漏。我也需要添加它们吗?

确切地说,我不参加了

using is_always_equal = std::true_type

std::allocator_traits提供,因为我的分配器为空,但将成为std::allocator的接口的一部分。

[我也忽略了pointerconst_pointerreferenceconst_referencerebindaddress,它们全部由std::allocator_traits提供,并且在C ++ 17中已弃用std::allocator的界面。

如果您认为需要定义所有这些以匹配std::allocator的界面,那么请考虑将它们添加到代码中。

c++ c++17 allocator
1个回答
0
投票

分配器具有特定的requirements,如果它们将由std::vectorstd::vector之类的类使用。由于std::basic_string是此类的默认模板参数,因此任何专业化都应满足要求。

添加模板专业化

仅当声明依赖于至少一个程序定义的类型并且该专业化满足原始模板的所有要求时,才允许将任何标准库类(自C ++ 20起)的模板专业化添加到命名空间std中,除非禁止这种专业化。

您已经声明了一些typedef和一些成员,但您甚至都没有声明过基本内容,例如std::basic_stringstd::allocator<T>

因此,您的“分配器”类可以用于概念的初步证明,您可以在需要分配器的模板中使用它,并且如果您的程序以有限的方式使用它,则它甚至可以工作。

但是在满足要求之前,它是不合规的,您不能相信它在所有情况下都能正常工作。

© www.soinside.com 2019 - 2024. All rights reserved.