• c++11 动态内存管理-分配器 (std::allocator)


    定义于头文件 
    1. template< class T >struct allocator; (1)
    2. template<>struct allocator<void>; (2) (C++17 中弃用) (C++20 中移除)

    std::allocator 类模板是所有标准库容器所用的默认分配器 (Allocator) ,若不提供用户指定的分配器。默认分配器无状态,即任何给定的 allocator 实例可交换、比较相等,且能解分配同一 allocator 类型的任何其他实例所分配的内存。

    对 void 的显式特化缺少成员 typedef referenceconst_referencesize_typedifference_type 。此特化不声明成员函数。

    (C++20 前)
    所有自定义分配器必须也无状态。(C++11 前)
    自定义分配器可以含有状态。每个容器或其他具分配器对象存储一个提供的分配器实例,并通过 std::allocator_traits 控制分配器替换。(C++11 起)
    默认分配器满足分配器完整性要求。(C++17 起)

    构造函数 

    std::allocator<T>::allocator

    allocator() throw();

    (1)(C++11 前)

    allocator() noexcept;

    (C++11 起)
    (C++20 前)

    constexpr allocator() noexcept;

    (C++20 起)

    allocator( const allocator& other ) throw();

    (2)(C++11 前)

    allocator( const allocator& other ) noexcept;

    (C++11 起)
    (C++20 前)

    constexpr allocator( const allocator& other ) noexcept;

    (C++20 起)

    template< class U >
    allocator( const allocator& other ) throw();

    (3)(C++11 前)

    template< class U >
    allocator( const allocator& other ) noexcept;

    (C++11 起)
    (C++20 前)

    template< class U >
    constexpr allocator( const allocator& other ) noexcept;

    (C++20 起)

    构造默认分配器。因为默认分配器是无状态的,故构造函数无可见效应。

    参数

    other-用以构造的另一 allocator

     

    析构函数

    std::allocator<T>::~allocator

    ~allocator();

    (C++20 前)

    constexpr ~allocator();

    (C++20 起)

    销毁默认分配器。

    获得对象的地址,即使重载了 operator&

    std::allocator<T>::address

    pointer address( reference x ) const;

    (C++11 前)

    pointer address( reference x ) const noexcept;

    (C++11 起)
    (C++17 中弃用)
    (C++20 中移除)

    const_pointer address( const_reference x ) const;

    (C++11 前)

    const_pointer address( const_reference x ) const noexcept;

    (C++11 起)
    (C++17 中弃用)
    (C++20 中移除)

    返回 x 的实际地址,即使存在重载的 operator& 。

    参数

    x-要获取地址的对象

    返回值

    x 的实际地址。

    分配未初始化的存储

    std::allocator<T>::allocate

    pointer allocate( size_type n, const void * hint = 0 );

    (1)(C++17 前)

    T* allocate( std::size_t n, const void * hint);

    (C++17 起)
    (弃用)
    (C++20 中移除)

    T* allocate( std::size_t n );

    (2)(C++17 起)
    (C++20 前)

    [[nodiscard]] constexpr T* allocate( std::size_t n );

    (C++20 起)

    调用 ::operator new(std::size_t) 或 ::operator new(std::size_t, std::align_val_t) (C++17 起)分配 n * sizeof(T) 字节的未初始化存储,但何时及如何调用此函数是未指定的。指针 hint 可用于提供引用的局部性:若实现支持,则 allocator 会试图分配尽可能接近 hint 的新内存块。

    参数

    n-要分配存储的对象数
    hint-指向临近内存位置的指针

    返回值

    指向适当对齐并足以保有 T 类型的 n 个对象数组的内存块首字节的指针。

    异常

    若分配失败则抛出 std::bad_alloc 。

    注解

    遣词“未指定何时及如何”令标准库容器可以组合或优化掉堆分配,即使对直接调用 ::operator new 禁止这种优化。例如 libc++ 实现了它( [1][2]

     

    解分配存储

    std::allocator<T>::deallocate

    void deallocate( T* p, std::size_t n );

    (C++20 前)

    constexpr void deallocate( T* p, std::size_t n );

    (C++20 起)

    从指针 p 所引用的存储解分配,指针必须是通过先前对 allocate() 获得的指针。

    参数 n 必须等于对原先生成 p 的 allocate() 调用的首参数;否则行为未定义。

    调用 ::operator delete(void*) 或 ::operator delete(void*, std::align_val_t) (C++17 起),但何时及如何调用是未指定的。

    参数

    p-allocate() 获得的指针
    n-先前传递给 allocate() 的对象数

    返回值

    (无)

    调用示例

    1. ​#include <memory>
    2. #include <iostream>
    3. #include <string>
    4. int main()
    5. {
    6. std::allocator<int> ai; // int 的默认分配器
    7. int* a = ai.allocate(10); // 10个 int 的空间
    8. for (int i = 0; i < 10; i++)
    9. {
    10. ai.construct(a + i, i); // 构造 int
    11. }
    12. for (int i = 0; i < 10; i++)
    13. {
    14. std::cout << a[i] << '\n';
    15. }
    16. ai.deallocate(a, 10); // 解分配10个 int 的空间
    17. std::allocator<std::string> as; // string 的默认分配器
    18. std::string * s = as.allocate(10); // 10string 的空间
    19. for (int i = 0; i < 10; i++)
    20. {
    21. as.construct(s + i, std::to_string(i) + "-string"); // 构造 int
    22. }
    23. for (int i = 0; i < 10; i++)
    24. {
    25. std::cout << s[i] << '\n';
    26. }
    27. as.deallocate(s, 10); // 解分配10个 int 的空间
    28. }

    输出

     

    返回最大的受支持分配大小

    std::allocator<T>::max_size

    size_type max_size() const throw();

    (C++11 前)

    size_type max_size() const noexcept;

    (C++11 起)
    (C++17 中弃用)
    (C++20 中移除)

    返回理论上可行的 n 最大值,对于它 allocate(n, 0) 调用可能成功。

    大部分实现中,它返回 std::numeric_limits::max() / sizeof(value_type) 。

    参数

    (无)

    返回值

    受支持的最大分配大小

     调用示例

    1. #include <memory>
    2. #include <iostream>
    3. #include <string>
    4. struct Foo
    5. {
    6. Foo() {}
    7. };
    8. int main()
    9. {
    10. std::allocator<char> ac; // char 的默认分配器
    11. std::allocator<int> ai; // int 的默认分配器
    12. std::allocator<double> ad; // double 的默认分配器
    13. std::allocator<std::string> as; // string 的默认分配器
    14. std::allocator<Foo> af; // Foo 的默认分配器
    15. std::cout << "char max_size() " << ac.max_size() << '\n';
    16. std::cout << "int max_size() " << ai.max_size() << '\n';
    17. std::cout << "double max_size() " << ad.max_size() << '\n';
    18. std::cout << "as max_size() " << as.max_size() << '\n';
    19. std::cout << "Foo max_size() " << af.max_size() << '\n';
    20. }

    输出 

     

    在分配的存储构造对象

    std::allocator<T>::construct

    void construct( pointer p, const_reference val );

    (1)(C++11 前)

    template< class U, class... Args >
    void construct( U* p, Args&&... args );

    (2)(C++11 起)
    (C++17 中弃用)
    (C++20 中移除)

    用布置 new ,在 p 所指的未初始化存储中构造 T 类型对象。

    1) 调用 new((void *)p) T(val)

    2) 调用 ::new((void *)p) U(std::forward(args)...)

    参数

    p-指向未初始化存储的指针
    val-用作复制构造函数参数的值
    args...-所用的构造函数参数

    返回值

    (无)

     

    析构在已分配存储中的对象

    std::allocator<T>::destroy

    void destroy( pointer p );

    (C++11 前)

    template< class U >
    void destroy( U* p );

    (C++11 起)
    (C++17 中弃用)
    (C++20 中移除)

    调用 p 所指的对象的析构函数

    1) 调用 ((T*)p)->~T()

    2) 调用 p->~U()

    参数

    p-指向要被销毁的对象的指针

    返回值

    (无)

    比较两个分配器实例

    operator==,!=(std::allocator)

    template< class T1, class T2 >
    bool operator==( const allocator& lhs, const allocator& rhs ) throw();

    (1)(C++11 前)

    template< class T1, class T2 >
    bool operator==( const allocator& lhs, const allocator& rhs ) noexcept;

    (C++11 起)
    (C++20 前)

    template< class T1, class T2 >
    constexpr bool operator==( const allocator& lhs, const allocator& rhs ) noexcept;

    (C++20 起)

    template< class T1, class T2 >
    bool operator!=( const allocator& lhs, const allocator& rhs ) throw();

    (2)(C++11 前)

    template< class T1, class T2 >
    bool operator!=( const allocator& lhs, const allocator& rhs ) noexcept;

    (C++11 起)
    (C++20 前)

    比较二个默认分配器。因为默认分配器无状态,故二个默认分配器始终相等。

    1) 返回 true

    2) 返回 false

    参数

    lhs, rhs-要比较的默认分配器

     调用示例

    1. #include <memory>
    2. #include <iostream>
    3. #include <string>
    4. int main()
    5. {
    6. std::allocator<int> a1; // int 的默认分配器
    7. int* a = a1.allocate(1); // 一个 int 的空间
    8. a1.construct(a, 7); // 构造 int
    9. std::cout << a[0] << '\n';
    10. a1.deallocate(a, 1); // 解分配一个 int 的空间
    11. // string 的默认分配器
    12. std::allocator<std::string> a2;
    13. // 同上,但以 a1 的重绑定获取
    14. decltype(a1)::rebind<std::string>::other a2_1;
    15. // 同上,但通过 allocator_traits 由类型 a1 的重绑定获取
    16. std::allocator_traits<decltype(a1)>::rebind_alloc<std::string> a2_2;
    17. std::string* s = a2.allocate(2); // 2string 的空间
    18. a2.construct(s, "foo");
    19. a2.construct(s + 1, "bar");
    20. std::cout << s[0] << ' ' << s[1] << '\n';
    21. a2.destroy(s);
    22. a2.destroy(s + 1);
    23. a2.deallocate(s, 2);
    24. }

  • 相关阅读:
    MySQL浅析之架构概览
    【C++入门】(纯)虚函数和多态、抽象类、接口
    matplotlib画latex表格
    Linux应用开发 - 读写锁
    Hyerf 初体验
    【SQL】595. 大的国家
    MATLAB向量
    解决远程git服务器路径改变导致本地无法push的问题
    超参数调整, 批量正则化 和多元分类器
    ChatGPT高效提问——角色提示
  • 原文地址:https://blog.csdn.net/qq_40788199/article/details/126797798