简体   繁体   English

在 C++ 中使用 std::allocator 而不是 new 有什么好处?

[英]What's the advantage of using std::allocator instead of new in C++?

I've just read about std::allocator .我刚刚阅读了std::allocator In my opinion, it is more complicated to use it instead of using new and delete .在我看来,使用它而不是使用newdelete更复杂。

With allocator we must explicitly allocate heap memory, construct it, destroy it, and then finally deallocate the memory.使用allocator我们必须显式分配堆内存,构造它,销毁它,最后释放内存。 So why was it created?那么它为什么被创建呢?

In which cases can it be used and when should it be used instead of new and delete?在什么情况下可以使用它,什么时候应该使用它来代替 new 和 delete?

In my opinion, it is more complicated to use it instead of using new and delete. 在我看来,使用它而不是使用new和delete更复杂。

Yes, but it is not meant to replace new and delete , it serves a different purpose. 是的,但它并不是要取代newdelete ,它有不同的用途。

With allocator we must explicitly allocate heap memory, construct it, destroy it, and then finally deallocate the memory. 使用allocator,我们必须显式分配堆内存,构造它,销毁它,然后最终释放内存。

So why was it created? 那它为什么会被创造出来?

Because sometimes you want to separate allocation and construction into two steps (and similarly to separate destruction and deallocation into two steps). 因为有时您希望将分配和构造分成两个步骤(类似于将销毁和解除分配分成两个步骤)。 If you don't want to do that, don't use an allocator, use new instead. 如果您不想这样做,请不要使用分配器,而是使用new

In which cases can it be used and when should it be used instead of new and delete? 在哪些情况下可以使用它何时应该使用而不是新的和删除?

When you need the behaviour of an allocator, not the behaviour of new and delete , obviously! 当你需要分配器的行为时,显然不是newdelete的行为! The typical case is when implementing a container. 典型的情况是实现容器。

Consider the following code: 请考虑以下代码:

std::vector<X> v;
v.reserve(4);        // (1)
v.push_back( X{} );  // (2)
v.push_back( X{} );  // (3)
v.clear();           // (4)

Here line (1) must allocate enough memory for four objects, but not construct them yet. 这里第(1)行必须为四个对象分配足够的内存,但还没有构造它们。 Then lines (2) and (3) must construct objects into the allocated memory. 然后第(2)和(3)行必须将对象构造到已分配的内存中。 Then line (4) must destroy those objects, but not deallocate the memory. 然后第(4)行必须销毁这些对象,但不能解除内存的释放。 Finally, in the vector's destructor, all the memory can be deallocated. 最后,在向量的析构函数中,可以释放所有内存。

So the vector cannot just use new X() or delete &m_data[1] to create and destroy the objects, it must perform allocation/deallocation separately from construction/destruction. 因此,向量不能只使用new X()delete &m_data[1]来创建和销毁对象,它必须与构造/销毁分开执行分配/释放。 A container's allocator template argument defines the policy that should be used for (de)allocating memory and constructing/destructing objects, allowing the container's use of memory to be customised. 容器的allocator模板参数定义了应该用于(de)分配内存和构造/破坏对象的策略,允许容器使用内存进行自定义。 The default policy is the std::allocator type. 默认策略是std::allocator类型。

So you use an allocator when an allocator is required (such as when using a container) and you use std::allocator when you don't want to provide a custom allocator and just want the standard one. 因此,当需要分配器时(例如使用容器时)使用std::allocator当您不想提供自定义分配器并且只想要标准std::allocator时使用std::allocator

You don't use an allocator as a replacement for new and delete . 您不使用分配器来替换newdelete

std::allocator is the default memory allocator for the standard library containers, and you can substitute your own allocators. std::allocator是标准库容器的默认内存分配器,您可以替换自己的分配器。 This allows you to control how the standard containers allocate memory. 这允许您控制标准容器如何分配内存。 But I don't think that your question is about std::allocator specifically, but rather the strategy of allocating memory, then constucting objects in that memory, rather than using new T[N] , for example. 但我不认为你的问题是关于std::allocator ,而是分配内存的策略,然后在该内存中构造对象,而不是使用new T[N]

And the reason for that is that new T[N] doesn't allow you control over what constructors are called. 原因是new T[N]不允许您控制调用的构造函数。 And it forces you to construct all your objects at the same time. 它迫使你同时构建所有对象。 This is terrible for the purposes of, for example, std::vector where you only want to allocate occasionally. 这对于std::vector是很糟糕的,你只想偶尔分配它。

With a raw memory allocator, you can allocate a certain amount of memory, which determines your capacity. 使用原始内存分配器,您可以分配一定量的内存,从而确定容量。 Then, as the user adds items to the vector (using the constructor of their choice), you can construct objects in place in this memory. 然后,当用户向向量添加项目时(使用他们选择的构造函数),您可以在此内存中构造对象。

Then when you run out of memory, you allocate more, typically twice as much. 然后当你的内存不足时,你会分配更多,通常是两倍。 If std::vector used new T[N] , it would have to reallocate every time you wanted to add or remove an element, which would be terrible for performance. 如果std::vector使用了new T[N] ,则每次要添加或删除元素时都必须重新分配,这对性能来说太糟糕了。 You would also be forced to use the default constructor for all the objects, which puts an unnecessary restriction on the types of objects std::vector can hold. 您还将被迫对所有对象使用默认构造函数,这对std::vector可以容纳的对象类型设置了不必要的限制。

Allocators are a very important concept in the STL. 分配器是STL中非常重要的概念。 Every container is capable to take an allocator as argument. 每个容器都能够将分配器作为参数。 Then allocations will be performed using this allocator, and not the standard one. 然后将使用此分配器执行分配,而不是标准分配器。

This is useful eg for allocating objects of the same size in a pool, to improve performance, or might be necessary if there's a special area of memory where your objects need to live. 这对于在池中分配相同大小的对象,提高性能,或者如果您的对象需要存在特殊的内存区域可能是必要的。

The steps of allocating and constructing are separate because eg for vector ( std::vector::reserve ) it's important to be able to allocate memory for future use, but not (yet) create objects therein. 分配和构造的步骤是分开的,因为例如对于vector( std::vector::reserve ),重要的是能够分配存储器以供将来使用,但是(还)不在其中创建对象。

As an example you could write an allocator as a class, containing an fixed size array, and use that array to provide memory for some standard container. 作为示例,您可以将分配器编写为包含固定大小数组的类,并使用该数组为某个标准容器提供内存。 Then you can have an instance of that class on the stack and thus completely avoid heap allocations for some part of your programm. 然后,您可以在堆栈上拥有该类的实例,从而完全避免程序的某些部分的堆分配。

See more examples here in this SO post. 请参阅此SO帖子中的更多示例。

[...] when should it be used [...] [...]什么时候应该使用[...]

When you have specific needs, and most important when writing own generic containers. 当您有特定需求时,最重要的是在编写自己的通用容器时。

Your instinct is right. 你的直觉是对的。 In 90% of cases, use new . 在90%的情况下,使用new However, notice in structures like, say, the map data structure. 但是,请注意结构,例如地图数据结构。 One of its default template arguments is class Alloc = allocator<pair<const Key,T> , which defines how the class creates new instances of things and manages existing instances. 其默认模板参数之一是class Alloc = allocator<pair<const Key,T> ,它定义了类如何创建事物的新实例并管理现有实例。 In this way, you could theoretically create your own allocator and then use it for existing data structures. 通过这种方式,理论上您可以创建自己的分配器,然后将其用于现有数据结构。 Since new and delete are functions and not classes, it is necessary to have the std::allocator to represent them and make them valid template arguments. 由于newdelete是函数而不是类,因此必须使用std::allocator来表示它们并使它们成为有效的模板参数。

The std::allocator was created to allow developers more control of how memory is allocated. 创建std::allocator是为了让开发人员能够更好地控制内存的分配方式。 In many embedded systems, memory is constrained and in different types. 在许多嵌入式系统中,存储器受到约束并且具有不同的类型。 There may not be a huge amount. 可能没有太大的数额。 Also, memory allocation wants to be minimized to avoid fragmentation issues. 此外,希望最小化内存分配以避免碎片问题。

The allocator also allows for allocation from different memory pools. 分配器还允许从不同的内存池进行分配。 So for example, allocating small sized blocks would be more efficient from a small block memory pool. 因此,例如,从小块内存池中分配小尺寸块将更有效。

The reason for this STL member is to give the developer more control over memory. 这个STL成员的原因是让开发人员更好地控制内存。 What I mean by this is, for instance, the new operator is not really just one operation per se. 我的意思是,例如,new运算符本身并不仅仅是一个操作。 At its most basic, it performs a reservation of memory AND then fills that space with the object. 最基本的是,它执行内存预留,然后用该对象填充该空间。

Although I cannot on top of my head come up with a specific, real-world case scenario, you should use std::allocator and such when, perhaps, the destruction of a given object might impact other objects in memory. 虽然我不能在脑海中提出一个特定的,真实世界的案例场景,但是你应该使用std::allocator ,这可能会破坏给定对象可能会影响内存中的其他对象。

Let's say, for the sake of argument, you created some kind of vector which each element is double-linked to some other object in memory and you want, at the time of deletion of said vector, the objects linked to remove the reference back to it. 让我们说,为了论证,你创建了某种向量,每个元素都与内存中的其他对象双链接,你想要在删除所述向量时,链接的对象将删除引用返回给它。

new and delete are the direct way to create an object in dynamic memory and initialize it. newdelete是在动态内存中创建对象并初始化它的直接方法。 Allocators are much more though, because they offer complete control over the aforementioned phases. 分配器更多,因为它们提供对上述阶段的完全控制。

With allocator we must explicitly allocate heap memory, construct it, destroy it, and then finally deallocate the memory. 使用allocator,我们必须显式分配堆内存,构造它,销毁它,然后最终释放内存。

Indeed allocators are not supposed to be used for "normal" code where new and delete would equally be fine. 实际上,分配器不应该用于“普通”代码,其中newdelete同样可以。 Consider a class like std::map , often implemented as a tree: do you need to deallocate the whole leaf whenever an object held is deleted? 考虑像std::map这样的类,通常实现为树:每当删除对象时,是否需要释放整个叶子? Allocators allow you do destruct that object, but keep the memory so that you don't have to require it again. 分配器允许您破坏该对象,但保留内存,以便您不必再次需要它。

Further, you may specialize an allocator for a certain type if you know more optimized methods for its control which is not possible for new and delete . 此外,如果您知道更多针对其控制的优化方法,那么您可以专门为某个类型分配器,这对于newdelete是不可能的。

You are confused.你很困惑。 std::allocator calls/uses new and delete . std::allocator调用/使用newdelete It is simply another level in the C++ memory hierarchy, used to serve the various needs of the C++ standard library, particularly the containers, but other types too.它只是 C++ 内存层次结构中的另一个级别,用于满足 C++ 标准库的各种需求,尤其是容器,但其他类型也是如此。 The C++ library containers use the allocator to automatically manage the memory of the contained elements. C++ 库容器使用分配器来自动管理所包含元素的内存。 Without it, things would be more cumbersome and thus more difficult to use.没有它,事情会更麻烦,因此更难使用。 Furthermore an allocator can be used to perform different techniques of memory management, eg stack allocation, linear allocation, heap allocation, pool allocation etc.此外,分配器可用于执行不同的内存管理技术,例如堆栈分配、线性分配、堆分配、池分配等。

C++ memory "hierarchy" C++ 内存“层次结构”

_________________
|Applications   |
|_______________|
      |
______↓_______________________
|C++ library (std::allocator)|
|____________________________|
      |
______↓______________________________________________________________________________
|C++ primitives (new/delete, new[]/delete[], ::operator new()/::operator delete())  |
|___________________________________________________________________________________|
      |
______↓______
|malloc/free|
|___________|
      |
______↓______________
|OS APIs, syscalls  |
|___________________|

This is the normal flow of calls, but an application can instead call malloc/free, or new/delete or even the OS APIs directly.这是正常的调用流程,但应用程序可以改为直接调用 malloc/free、new/delete 甚至 OS API。 You see it's ALL an abstraction.你看这一切都是抽象的。 The level above abstracts the more difficult nature of the one and wraps it in an easier to use package.上面的级别抽象了一个更困难的性质,并将其包装在一个更易于使用的包中。

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

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