为什么要求自定义分配器是可复制的
Why the requirement for custom allocators to be copyconstructible?
C++11标准(或至少是这个工作草案(要求实现Allocator
概念的类提供复制构造函数。
这是有意义的,但是当分配器类中允许状态时,提供复制构造函数可能不是可取的。 例如,如果分配器实现了某种板分配系统或内存池,则在其中维护内部自由列表。 在我看来,这样的分配器应该始终移动,而不是复制。 实际上复制它需要分配新的存储,然后完全复制原始分配器的内部状态,包括所有可用内存块、自由列表等。 (或者"复制"一个Allocator
只是意味着返回Allocator()
,即返回一个新的默认构造的分配器?
实际上,复制状态分配器似乎是完全不必要的,因为据我所知,在实践中,复制构造分配器没有真正的通用用例。 没有Container
实际复制分配器 - C++11 容器将在容器复制构造函数中调用Allocator::select_on_container_copy_construction
,通常只返回Allocator()
。 然后容器通常只是从另一个容器中逐个元素复制,可能只需调用 Container::insert
.
当然,优化的容器实现可能会使用有关容器结构的内部知识做一些更复杂的事情,但仍然没有人会复制构造other.get_allocator()
- 容器只会调用other.get_allocator().select_on_container_copy_construction()
来获取默认构造的分配器。
那么,为什么我们要求分配器本身必须是可复制的呢? 搬家建设不应该足够吗?
注意:需要明确的是,这个问题不是为什么 c++ 中的分配器需要复制构造函数的重复。 这个问题专门询问std::allocator
(无状态(,而我询问的是实现Allocator
概念的自定义分配器。
重新声明
"> 没有
Container
实际上复制分配器
可能是这样(我没有测试过(,std::string
可能被视为非Container
,但仍然:
#include <string>
#include <iostream>
#include <memory> // std::allocator
template< class Type >
struct Alloc
: std::allocator<Type>
{
using Base = std::allocator<Type>;
template< class Other >
struct rebind
{
using other = Alloc<Other>;
};
Alloc() {}
Alloc( Alloc<Type> const& other )
: Base( other )
{ std::clog << "Alloc::<copy>n"; }
template<class Other>
Alloc( Alloc<Other> const& other )
: Base( other )
{ std::clog << "Alloc::<generic-copy>n"; }
};
auto main() -> int
{
using namespace std;
basic_string< char, char_traits<char>, Alloc<char> > a = "A", b = "B";
a = b;
}
带可视C++的输出:
分配::<副本>分配::<副本>副本>副本>
使用 g++,分配器复制操作的数量更多。
标准库 容器通常具有构造函数,这些构造函数采用对现有分配器对象的引用const
;例如 自 C++20 年以来vector
constexpr explicit vector( const Allocator& alloc ) noexcept;
移动构造不是合适的语义,因为不能从alloc
中删除任何资源,因为它是const
。复制构造对于此目的是必需的,因为alloc
的生存期未指定,并且alloc
不能用于状态修改分配。参见 为什么分配器常量在向量中?。
您可以使用一个引用基础分配类的分配器,以避免复制内存管理数据,或在多个分配器之间共享数据。但是,只要提供适当的复制构造函数或成员函数(可以是对默认构造函数的调用(,就可以安全地在分配器中使用状态来提供每容器内存select_on_container_copy_construction
。
给定一个分配器A
,
std::allocator_traits<A>::select_on_container_copy_construction
如果A
不提供成员函数select_on_container_copy_construction
则返回A
的副本。
- 简单可复制与可简单复制
- reinterpret_cast,只读访问,简单的可复制类型,会出什么问题?
- 对于参加可复制和可移动类的访问者来说,应该有多少过载?
- 可变参数宏:无法通过"..."传递非平凡可复制类型的对象
- 为什么 std::atomic<std::string> 会给出微不足道的可复制错误?
- 我可以隐式地创建一个琐碎的可复制类型吗
- 是std::memcpy在不同的可复制类型之间的未定义行为
- 为什么一对常量是微不足道的可复制的,而对不是?
- 在一个微不足道的可复制结构中,移动语义应该实现吗?
- 从标准容器重新绑定和复制分配器
- C++ 如何在容器类复制构造函数中复制分配器对象
- 防止作用域枚举可复制/可移动
- C :对象上的可复制视图
- 防御性地应用 std::move 到平凡可复制的类型是否不可取
- 为什么 std::function 本身是可复制构造的类型?
- C++不可复制的 lambda 的行为是可复制的
- 错误:无法通过'...'传递非平凡可复制类型的对象'class boost::filesystem::path'
- 不能让类是微不足道的可复制的。我做错了什么?
- 使用临时存储区复制普通的可复制类型:允许吗
- 为什么要求自定义分配器是可复制的