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

发布于 2024-09-06 11:19:35 字数 1104 浏览 10 评论 0原文

在 C 中,标准内存处理函数是 malloc()realloc()free()。然而,C++ stdlib 分配器仅并行其中两个:没有重新分配函数。当然,不可能与realloc()完全相同,因为简单地复制内存并不适合非聚合类型。但是,例如,此函数是否会存在问题:

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

其中

  • ptr 之前已使用相同的分配器为 num_now 对象分配了;
  • num_requested >= num_now;

语义如下:

  • 如果分配器可以将 ptr 处的给定内存块从 num_now 对象的大小扩展到 num_requested 对象,那么它就会这样做(留下额外的内存块)内存未初始化)并返回 true ;
  • 否则它什么都不做并返回false

当然,这不是很简单,但据我了解,分配器主要用于容器,而容器的代码通常已经很复杂了。

给定这样一个函数,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

无法完全更改内存大小的分配器可以通过无条件返回 false 来实现这样的函数; 。

可重新分配的分配器实现是否太少以至于不值得去打扰?还是有一些我忽略的问题?

In C the standard memory handling functions are malloc(), realloc() and free(). However, C++ stdlib allocators only parallel two of them: there is no reallocation function. 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. 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;
  • 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;
  • else it does nothing and returns 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):

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;.

Are there so few reallocation-capable allocator implementation that it wouldn't worth it to bother? Or are there some problems I overlooked?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

余罪 2024-09-13 11:19:35

从:
http://www.sgi.com/tech/stl/alloc.html" sgi.com/tech/stl/alloc.html

这可能是最值得怀疑的
设计决策。它会有
可能更有用一点
提供重新分配的版本
要么改变了大小
现有对象,无需复制或
返回 NULL。这样就可以了
对于具有副本的对象直接有用
构造函数。它还会有
避免了不必要的复制
其中原始对象没有
已完全填写。

不幸的是,这会
禁止使用 C 中的 realloc
图书馆。这反过来又会增加
许多分配器的复杂性
实施,并且会做出
与内存调试交互
工具比较难。于是我们决定
反对这种替代方案。

From:
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. 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. 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.

许一世地老天荒 2024-09-13 11:19:35

这实际上是 Alexandrescu 指出的标准分配器的设计缺陷(不是运算符 new[]/delete[],而是最初用于实现 std::vector 的 stl 分配器,例如)。

realloc 的发生速度明显快于 malloc、memcpy 和 free。然而,虽然可以调整实际内存块的大小,但它也可以将内存移动到新位置。在后一种情况下,如果内存块由非 POD 组成,则在重新分配后,所有对象都需要被销毁并复制构造。

标准库需要适应这种情况的主要内容是作为标准分配器公共接口一部分的重新分配函数。像 std::vector 这样的类当然可以使用它,即使默认实现是 malloc 新大小的块并释放旧的块。它需要是一个能够销毁和复制构造内存中对象的函数,但如果它这样做,它就不能以不透明的方式处理内存。这里涉及到一点复杂性,并且需要更多的模板工作,这可能就是它被从标准库中省略的原因。

std::vector<...>::reserve 是不够的:它解决了可以预期容器大小的不同情况。对于真正可变大小的列表,realloc 解决方案可以使像 std::vector 这样的连续容器更快,特别是如果它可以处理内存块在不移动的情况下成功调整大小的情况,在这种情况下它可以省略调用 copy内存中对象的构造函数和析构函数。

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, e.g.).

A realloc can occur significantly faster than a malloc, memcpy, and 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.

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. 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. 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.

梦幻之岛 2024-09-13 11:19:35

您所要求的本质上就是 vector::reserve 所做的。如果没有对象的移动语义,就无法在不进行复制和销毁的情况下重新分配内存和移动对象。

What you're asking for is essentially what vector::reserve does. Without move semantics for objects, there's no way to reallocate memory and move the objects around without doing a copy and destroy.

鹿童谣 2024-09-13 11:19:35

我想这是上帝出错的事情之一,但我只是懒得写信给标准委员会。

应该有一个用于数组分配的 realloc:

p = renew(p) [128];

或类似的东西。

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.

留蓝 2024-09-13 11:19:35

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

Because of the object oriented nature of C++, and the inclusion of the various standard container types, I think it's simply that less focus was placed on direction memory management than in C. I agree that there are cases that a realloc() would be useful, but the pressure to remedy this is minimal, as almost all of the resulting functionality can be gained by using containers instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文