[英]Can I use an allocator object to free memory allocated by another allocator?
As far as I know, std::allocator
is introduced by the library to allocate uninitialized unconstructed blocks of memory.据我所知,库引入了
std::allocator
来分配未初始化的未构造内存块。 So:所以:
std::allocator<int> a;
auto ptr = a.allocate(100);
auto e = ptr;
while (e != ptr + 5)
a.construct(e++, 0);
for (auto tmp = ptr; tmp != e; )
std::cout << *tmp++ << ", ";
std::cout << std::endl;
std::allocator<int> a2;
std::allocator<int> a3 = a;
for (auto tmp = ptr; tmp != e; )
a.destroy(tmp++);
//for (auto tmp = ptr; tmp != e; )
// a2.destroy(tmp++); // is it UB using a2 here to destroy elements?
//for (auto tmp = ptr; tmp != e; )
// a3.destroy(tmp++); // is it UB also?
a.deallocate(ptr, 100); // ok
//a2.deallocate(ptr, 100); // UB or OK?
//a3.deallocate(ptr, 100); // UB or ok?
What I am not sure about is whether using another allocator a2
, a3
objects (one of them) to free (deallocate) memory allocated by a
is Undefined Behavior?我不确定的是,使用另一个分配器
a2
、 a3
对象(其中一个)来释放(解除分配)由a
分配的内存是否是未定义行为?
If it is OK why classes like std::vector
has an allocator object and not just create a temporary one to alloc/dealloc memory?如果可以的话,为什么像
std::vector
这样的类有一个分配器对象,而不仅仅是创建一个临时对象来分配/释放内存?
Please clarify the questions above.请澄清以上问题。
My reading of the standard says this is undefined behavior, unless the allocators compare equal.我对标准的阅读说这是未定义的行为,除非分配器比较相等。 Table 34: Cpp17Allocator requirements [tab:cpp17.allocator] states for
表 34:Cpp17Allocator 要求 [tab:cpp17.allocator]状态
a.deallocate(p,n)
that那
Requires:
p
shall be a value returned by an earlier call toallocate
that has not been invalidated by an intervening call todeallocate
.要求:
p
应是先前对allocate
调用返回的值,该值未被中间调用对deallocate
无效。n
shall match the value passed toallocate
to obtain this memory.n
应匹配传递给allocate
以获得此内存的值。
Where a
is an lvalue of the allocator type.其中
a
是分配器类型的左值。 Since allocate
is a member function I interpret the use of allocate
in the quoted text to mean a.allocate
which would mean you need the same or equal object to deallocate what was allocated.由于
allocate
是一个成员函数,我将引用文本中allocate
的使用解释为a.allocate
,这意味着您需要相同或相等的对象来释放分配的内容。
This of course means that something like vector
couldn't make a temporary when it needed and would need to keep the allocator as a member.这当然意味着像
vector
这样的东西在需要时不能临时创建,并且需要将分配器保留为成员。
You can read about the specification for allocators here: https://en.cppreference.com/w/cpp/named_req/Allocator .您可以在此处阅读有关分配器的规范: https : //en.cppreference.com/w/cpp/named_req/Allocator 。 They have changed a bit in different standard versions, but I will write about the C++17 and 20 renditions.
它们在不同的标准版本中略有变化,但我会写关于 C++17 和 20 的版本。
When you allocate memory with an allocator a1
, it can only be deallocated by a different allocator a2
if a1 == a2
.当您使用分配器
a1
分配内存时,如果a1 == a2
,它只能由不同的分配器a2
释放。Quote from the standard :引用标准:
a1 == a2
returnstrue
only if storage allocated from each can be deallocated via the other.仅当从每个分配的存储可以通过另一个解除分配时才返回
true
。
std::allocator<T>
is usually implemented as an empty type with no state. std::allocator<T>
通常实现为没有状态的空类型。 std::allocator<T>::is_always_equal::value
is true
, so all std::allocator<T>
objects are equal. std::allocator<T>::is_always_equal::value
为true
,所以所有std::allocator<T>
对象都相等。 Thus, both deallocations are well defined.因此,两种解除分配都得到了很好的定义。
If it was a stateful allocator, after AllocatorT a3 = a1
, a1 == a3
should be true
, so you are safe to deallocate with it.如果它是一个有状态的分配器,在
AllocatorT a3 = a1
, a1 == a3
应该是true
,所以你可以安全地释放它。 AllocatorT a2;
default constructs it, and a2 == a1
is probably not true, so you can't deallocate with a2
. default 构造它,并且
a2 == a1
可能不是真的,所以你不能用a2
解除分配。
In C++17, you could also do AllocatorT a3 = std::move(a1);
在 C++17 中,你也可以做
AllocatorT a3 = std::move(a1);
. . This means that you could no longer deallocate with
a1
(Unless a1 == a3
after the move), but only with a3
.这意味着您不能再使用
a1
解除分配(除非移动后a1 == a3
),而只能使用a3
。 This was changed in C++20, so you can only copy allocators.这在 C++20 中已更改,因此您只能复制分配器。
Currently, most container implementations contain an object that inherits from the allocator so that if it is empty, empty base optimisation is used so that it doesn't take any extra bytes.目前,大多数容器实现都包含一个从分配器继承的对象,因此如果它是空的,则使用空基优化,这样它就不会占用任何额外的字节。 So even if all objects are always the same, it doesn't hurt to use 0 extra bytes to store an allocator (And if it is stateful, an object needs to be stored anyway to deallocate).
因此,即使所有对象始终相同,使用 0 个额外字节来存储分配器也没有什么坏处(如果它是有状态的,则无论如何都需要存储一个对象以解除分配)。 In C++20, this will probably be implemented with the
[[no_unique_address]]
attribute for the same effect.在 C++20 中,这可能会使用
[[no_unique_address]]
属性来实现,以获得相同的效果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.