分配器:标准容器如何在内部工作?
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 的分配器创建了 S 的 vector =].
是合法的代码吗?我应该期待未定义的行为吗?还有什么?
我不完全理解这背后的魔力以及为什么 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>>
并且程序逻辑假定它们是同一类型,那将是一件坏事。
作为这个问题的例子,我将使用 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 的分配器创建了 S 的 vector =].
是合法的代码吗?我应该期待未定义的行为吗?还有什么?
我不完全理解这背后的魔力以及为什么 STL 允许用户这样做。
另一方面,rebind
之类的内容仅在 std::list
的文档中提及,我不知道它们是否也适用于这种情况。
在其他热力学中,如果它有效,我想知道它为什么有效(是 rebind
背后的吗?),否则我想知道为什么它被允许。
似乎有效,这让我很惊讶,但是:
你违约了。 allocator
必须满足 allocator<T>
和 cite cppreference 的要求,其中包括:
a.allocate(n)
| allocates storage suitable forn
objects of typeT
, 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 ifAllocator::value_type
is not the same asT
.",T
being the value type of the vector.
即。在您的情况下,行为未定义。
Table 98 -- 分配器感知容器要求在其第一行中说:
Requires:
allocator_type::value_type
is the same asX::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>>
并且程序逻辑假定它们是同一类型,那将是一件坏事。