分配器:标准容器如何在内部工作?

Allocators: how are the standard containers expected to work internally?

作为这个问题的例子,我将使用 std::vector
它在 documentation 中的定义如下:

template<class T, class Allocator = std::allocator<T>>
class vector;

正如预期的那样,如果 T 是它的类型,分配器应该偏向 T.
无论如何,下面的代码编译没有错误(至少,使用 GCC)并运行:

#include<vector>
#include<memory>
#include<string>

struct S {
    int i;
    double d;
    std::string s;
};

int main() {
    std::allocator<int> alloc;
    std::vector<S, std::allocator<int>> v{alloc};
    v.push_back(S{});
}

在这里,我通过使用专注于 int[=38 的分配器创建了 Svector =].

是合法的代码吗?我应该期待未定义的行为吗?还有什么?
我不完全理解这背后的魔力以及为什么 STL 允许用户这样做。
另一方面,rebind 之类的内容仅在 std::list 的文档中提及,我不知道它们是否也适用于这种情况。

在其他热力学中,如果它有效,我想知道它为什么有效(是 rebind 背后的吗?),否则我想知道为什么它被允许。

似乎有效,这让我很惊讶,但是:

你违约了。 allocator 必须满足 allocator<T>cite cppreference 的要求,其中包括:

a.allocate(n) | allocates storage suitable for n objects of type T, but does not construct them. May throw exceptions.

std::allocator<int>S 不适用,如 sizeof(int)!= sizeof(S)

所以,

I'd like to know why it is allowed.

这是不允许的。您的编译器无法检测到它。

@AlbertoM :

To add a quote from cppreference, in the std::vector page: " the behavior is undefined if Allocator::value_type is not the same as T.", T being the value type of the vector.

即。在您的情况下,行为未定义。

Table 98 -- 分配器感知容器要求在其第一行中说:

Requires: allocator_type::value_type is the same as X::value_type

客户端代码违反 Requires 子句会导致未定义的行为。

gcc 和 VS 没有检测到这个错误。它们通过将分配器重新绑定到适当的类型来允许代码工作。 libc++ 使用 static_assert.

主动检测此错误

http://melpon.org/wandbox/permlink/LVYEHfVIGoyZsii8

vector 的所有三种实现在这方面都是有效的。

libc++ 主动检测此错误的基本原理是更快地(在编译时)为您找到错误。如果在大型程序中有两个向量:vector<int, some_allocator<int>>vector<int, some_allocator<long>> 并且程序逻辑假定它们是同一类型,那将是一件坏事。