简体   繁体   English

为什么 C++ 分配器中没有重新分配功能?

[英]Why is there no reallocation functionality in C++ allocators?

In C the standard memory handling functions are malloc() , realloc() and free() .在 C 中,标准的内存处理函数是malloc()realloc()free() However, C++ stdlib allocators only parallel two of them: there is no reallocation function.然而,C++ stdlib 分配器只并行其中两个:没有重新分配函数。 Of course, it would not be possible to do exactly the same as realloc() , because simply copying memory is not appropriate for non-aggregate types.当然,不可能与realloc()完全相同,因为简单地复制内存不适用于非聚合类型。 But would there be a problem with, say, this function:但是,比如说,这个函数会不会有问题:

bool reallocate (pointer ptr, size_type num_now, size_type num_requested);

where在哪里

  • ptr is previously allocated with the same allocator for num_now objects; ptr之前为num_now对象分配了相同的分配器;
  • num_requested >= num_now ; num_requested >= num_now ;

and semantics as follows:和语义如下:

  • if allocator can expand given memory block at ptr from size for num_now objects to num_requested objects, it does so (leaving additional memory uninitialized) and returns true ;如果分配器可以将ptr处的给定内存块从num_now对象的大小num_nownum_requested对象,它num_requested (留下未初始化的额外内存)并返回true
  • else it does nothing and returns false .否则它什么都不做并返回false

Granted, this is not very simple, but allocators, as I understand, are mostly meant for containers and containers' code is usually complicated already.当然,这不是很简单,但据我所知,分配器主要用于容器,而容器的代码通常已经很复杂了。

Given such a function, std::vector , say, could grow as follows (pseudocode):给定这样的函数, std::vector可以如下增长(伪代码):

if (allocator.reallocate (buffer, capacity, new_capacity))
  capacity = new_capacity;     // That's all we need to do
else
  ...   // Do the standard reallocation by using a different buffer,
        // copying data and freeing the current one

Allocators that are incapable of changing memory size altogether could just implement such a function by unconditional return false;不能完全改变内存大小的分配器只能通过无条件return false;实现这样的功能return false; . .

Are there so few reallocation-capable allocator implementation that it wouldn't worth it to bother?是否有如此少的具有重新分配能力的分配器实现,以至于不值得打扰? Or are there some problems I overlooked?还是我忽略了一些问题?

From: http://www.sgi.com/tech/stl/alloc.html来自: http : //www.sgi.com/tech/stl/alloc.html

This is probably the most questionable design decision.这可能是最有问题的设计决策。 It would have probably been a bit more useful to provide a version of reallocate that either changed the size of the existing object without copying or returned NULL.提供一个重新分配的版本可能会更有用一些,该版本可以在不复制的情况下更改现有对象的大小或返回 NULL。 This would have made it directly useful for objects with copy constructors.这将使其直接适用于具有复制构造函数的对象。 It would also have avoided unnecessary copying in cases in which the original object had not been completely filled in.在原始对象未完全填充的情况下,它还可以避免不必要的复制。

Unfortunately, this would have prohibited use of realloc from the C library.不幸的是,这将禁止使用 C 库中的 realloc。 This in turn would have added complexity to many allocator implementations, and would have made interaction with memory-debugging tools more difficult.这反过来又会增加许多分配器实现的复杂性,并使与内存调试工具的交互更加困难。 Thus we decided against this alternative.因此我们决定反对这种选择。

This is actually a design flaw that Alexandrescu points out with the standard allocators (not operator new[]/delete[] but what were originally the stl allocators used to implement std::vector, eg).这实际上是 Alexandrescu 用标准分配器指出的一个设计缺陷(不是运算符 new[]/delete[],而是最初用于实现 std::vector 的 stl 分配器,例如)。

A realloc can occur significantly faster than a malloc, memcpy, and free. realloc 的发生速度明显快于 malloc、memcpy 和 free。 However, while the actual memory block can be resized, it can also move memory to a new location.但是,虽然可以调整实际内存块的大小,但它也可以将内存移动到新位置。 In the latter case, if the memory block consists of non-PODs, all objects will need to be destroyed and copy-constructed after the realloc.在后一种情况下,如果内存块由非 POD 组成,则所有对象都需要在重新分配后销毁和复制构造。

The main thing the standard library needs to accommodate this as a possibility is a reallocate function as part of the standard allocator's public interface.标准库需要适应这种可能性的主要事情是作为标准分配器公共接口的一部分的重新分配函数。 A class like std::vector could certainly use it even if the default implementation is to malloc the newly sized block and free the old one.像 std::vector 这样的类当然可以使用它,即使默认实现是 malloc 新大小的块并释放旧块。 It would need to be a function that is capable of destroying and copy-constructing the objects in memory though, it cannot treat the memory in an opaque fashion if it did this.它需要是一个能够销毁和复制构造内存中的对象的函数,但如果这样做,它就不能以不透明的方式处理内存。 There's a little complexity involved there and would require some more template work which may be why it was omitted from the standard library.那里涉及到一些复杂性,需要更多的模板工作,这可能是标准库中省略它的原因。

std::vector<...>::reserve is not sufficient: it addresses a different case where the size of the container can be anticipated. std::vector<...>::reserve 是不够的:它解决了可以预期容器大小的不同情况。 For truly variable-sized lists, a realloc solution could make contiguous containers like std::vector a lot faster, especially if it can deal with realloc cases where the memory block was successfully resized without being moved, in which case it can omit calling copy constructors and destructors for the objects in memory.对于真正可变大小的列表,realloc 解决方案可以使像 std::vector 这样的连续容器更快,特别是如果它可以处理内存块成功调整大小而不移动的 realloc 情况,在这种情况下,它可以省略调用 copy内存中对象的构造函数和析构函数。

What you're asking for is essentially what vector::reserve does.您所要求的本质上是vector::reserve作用。 Without move semantics for objects, there's no way to reallocate memory and move the objects around without doing a copy and destroy.如果没有对象的移动语义,就无法在不进行复制和销毁的情况下重新分配内存和移动对象。

I guess this is one of the things where god went wrong, but I was just too lazy to write to the standards committee.我想这是上帝出错的地方之一,但我懒得写信给标准委员会。

There should have been a realloc for array allocations:数组分配应该有一个重新分配:

p = renew(p) [128];

or something like that.或类似的东西。

由于 C++ 的面向对象性质,以及包含各种标准容器类型,我认为这只是与 C 相比,对方向内存管理的关注较少。我同意在某些情况下 realloc() 会很有用,但解决这个问题的压力很小,因为几乎所有产生的功能都可以通过使用容器来获得。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM