c++ - 为什么要求自定义分配器是可复制构造的?

标签 c++ c++11

C++11 标准(或至少 this working draft)要求实现 Allocator 概念的类提供复制构造函数。

这在所有分配器都必须是无状态的时候是有意义的,但是当分配器类中允许有状态时,可能不需要提供复制构造函数。例如,如果分配器实现了某种 slab 分配系统或内存池,它会在其中维护一个内部空闲列表。在我看来,这样的分配器应该总是被移动,而不是被复制。实际上复制它需要分配新的存储,然后完全复制原始分配器的内部状态,包括所有空闲内存块、空闲列表等。(或者“复制”一个 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() 获取默认构造的分配器。

那么为什么我们要求分配器本身必须是可复制构造的?搬家 build 还不够吗?


注意:明确地说,这个问题不是 why does allocator in c++ need a copy constructor? 的拷贝.这个问题专门询问 std::allocator(它是无状态的),而我问的是实现 Allocator 概念的自定义分配器。

最佳答案

再 claim

No Container actually copies an allocator

可能是这样(我没测试过),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;
}

用 Visual C++ 输出:

Alloc::<copy>
Alloc::<copy>

对于 g++,分配器复制操作的数量更多。

关于c++ - 为什么要求自定义分配器是可复制构造的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27462075/

相关文章:

c++ - if-指令宏比较

c++ - 从 MySQL DB 缓存数据 - 技术和适当的 STL 容器?

c++ - 在它自己的指针上模板化一个类?

c++ - 标准 C++11 是否保证 std::async(std::launch::async, func) 在单独的线程中启动 func?

c++ - GDI绘制的MFC的CScrollView如何实现缩放

c++ - 如何不在其他机器(x86_64 Linux)上运行 Pi 特定代码?

c++ - 2D opengl旋转导致 Sprite 失真

c++ - 由于标准容器中元素的默认初始化导致性能下降

c++ - 使用 Eigen 和 std::vector 的 SIGSEGV

c++ - 为什么 std::bind 不考虑功能元数?