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

定义于头文件 <memory>
template< class T >struct allocator;   (1)  

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<U>& other ) throw();

(3)(C++11 前)

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

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

template< class U >
constexpr allocator( const allocator<U>& 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() 的对象数

返回值

(无)

调用示例

​#include <memory>
#include <iostream>
#include <string>

int main()
{
    std::allocator<int> ai;   // int 的默认分配器
    int* a = ai.allocate(10);  // 10个 int 的空间
    for (int i = 0; i < 10; i++)
    {
        ai.construct(a + i, i);       // 构造 int
    }
    for (int i = 0; i < 10; i++)
    {
        std::cout << a[i] << '\n';
    }
    ai.deallocate(a, 10);      // 解分配10个 int 的空间

    std::allocator<std::string> as;   // string 的默认分配器
    std::string * s = as.allocate(10);  // 10个 string 的空间
    for (int i = 0; i < 10; i++)
    {
        as.construct(s + i, std::to_string(i) + "-string"); // 构造 int
    }
    for (int i = 0; i < 10; i++)
    {
        std::cout << s[i] << '\n';
    }
    as.deallocate(s, 10);      // 解分配10个 int 的空间
}

输出

 

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

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<size_type>::max() / sizeof(value_type) 。

参数

(无)

返回值

受支持的最大分配大小

 调用示例

#include <memory>
#include <iostream>
#include <string>

struct Foo
{
    Foo() {}
};

int main()
{
    std::allocator<char> ac;            // char 的默认分配器
    std::allocator<int> ai;             // int 的默认分配器
    std::allocator<double> ad;          // double 的默认分配器
    std::allocator<std::string> as;     // string 的默认分配器
    std::allocator<Foo> af;             // Foo 的默认分配器
    std::cout << "char max_size()       " << ac.max_size() << '\n';
    std::cout << "int max_size()        " << ai.max_size() << '\n';
    std::cout << "double max_size()     " << ad.max_size() << '\n';
    std::cout << "as max_size()         " << as.max_size() << '\n';
    std::cout << "Foo max_size()        " << af.max_size() << '\n';
}

输出 

 

在分配的存储构造对象

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>(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<T1>& lhs, const allocator<T2>& rhs ) throw();

(1)(C++11 前)

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

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

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

(C++20 起)

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

(2)(C++11 前)

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

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

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

1) 返回 true

2) 返回 false

参数

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

 调用示例

#include <memory>
#include <iostream>
#include <string>

int main()
{
    std::allocator<int> a1;   // int 的默认分配器
    int* a = a1.allocate(1);  // 一个 int 的空间
    a1.construct(a, 7);       // 构造 int
    std::cout << a[0] << '\n';
    a1.deallocate(a, 1);      // 解分配一个 int 的空间

    // string 的默认分配器
    std::allocator<std::string> a2;

    // 同上,但以 a1 的重绑定获取
    decltype(a1)::rebind<std::string>::other a2_1;

    // 同上,但通过 allocator_traits 由类型 a1 的重绑定获取
    std::allocator_traits<decltype(a1)>::rebind_alloc<std::string> a2_2;

    std::string* s = a2.allocate(2); // 2 个 string 的空间

    a2.construct(s, "foo");
    a2.construct(s + 1, "bar");

    std::cout << s[0] << ' ' << s[1] << '\n';

    a2.destroy(s);
    a2.destroy(s + 1);
    a2.deallocate(s, 2);
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值