我刚读到关于std::allocator的文章。在我看来,使用它比使用new和delete要复杂得多。
使用allocator,我们必须显式地分配堆内存,构造它,销毁它,然后最后释放内存。那么它为什么被创造出来呢?
在哪些情况下可以使用它,什么时候应该使用它而不是新的和删除的?
发布于 2015-07-11 15:57:23
std::allocator是标准库容器的默认内存分配器,您可以替换自己的分配器。这允许您控制标准容器如何分配内存。但我不认为您的问题是专门关于std::allocator的,而是分配内存的策略,然后在该内存中构造对象,而不是使用new T[N]。
其原因是new T[N]不允许您控制调用什么构造函数。它迫使你同时构造你的所有对象。这对于例如std::vector来说是很糟糕的,在这里您只想偶尔分配。
使用原始内存分配器,您可以分配一定数量的内存,这决定了您的容量。然后,当用户将项添加到向量(使用他们选择的构造函数)时,您可以在这个内存中构造合适的对象。
然后,当内存耗尽时,分配的内容会更多,通常是原来的两倍。如果std::vector使用new T[N],那么每当您想要添加或删除元素时,它都必须重新分配,这对性能影响很大。您还将被迫对所有对象使用默认构造函数,这对std::vector可以容纳的对象类型设置了不必要的限制。
发布于 2015-07-11 16:00:37
在我看来,使用它比使用新的和删除的更复杂。
是的,但它并不意味着要取代new和delete,它有着不同的用途。
使用分配器,我们必须显式地分配堆内存,构造它,销毁它,然后最后释放内存。 那么它为什么被创造出来呢?
因为有时您希望将分配和构造分离为两个步骤(类似于将销毁和退分配分离为两个步骤)。如果您不想这样做,不要使用分配器,而是使用new。
在哪些情况下可以使用它,什么时候应该使用它而不是新的和删除的?
显然,当您需要分配程序的行为时,而不是new和delete的行为!典型的情况是在实现容器时。
考虑以下代码:
std::vector<X> v;
v.reserve(4); // (1)
v.push_back( X{} ); // (2)
v.push_back( X{} ); // (3)
v.clear(); // (4)这里的第(1)行必须为四个对象分配足够的内存,但还不能构造它们。然后,行(2)和(3)必须将对象构造到分配的内存中。然后行(4)必须销毁这些对象,但不能释放内存。最后,在向量的析构函数中,可以释放所有内存。
因此向量不能仅仅使用new X()或delete &m_data[1]来创建和销毁对象,它必须与构造/销毁分开执行分配/去分配。容器的分配器模板参数定义了用于(De)分配内存和构造/析构对象的策略,允许定制容器对内存的使用。默认策略是std::allocator类型。
因此,当需要分配器时(例如在使用容器时)使用分配器,当您不想提供自定义分配器而只想要标准分配器时使用std::allocator。
您不使用分配器代替new和delete。
发布于 2015-07-11 15:46:49
分配器是STL中一个非常重要的概念。每个容器都能够接受一个分配器作为参数。然后将使用此分配程序执行分配,而不是使用标准分配程序。
这是有用的,例如,在池中分配相同大小的对象,以提高性能,或者,如果您的对象需要在内存中有特殊区域,则可能需要这样做。
分配和构造的步骤是分开的,因为对于向量(std::vector::reserve)来说,重要的是能够为将来的使用分配内存,而不是(目前)在其中创建对象。
作为一个示例,您可以将一个分配器编写为一个类,其中包含一个固定大小的数组,并使用该数组为某个标准容器提供内存。然后,您可以在堆栈上拥有该类的一个实例,从而完全避免为程序的某些部分分配堆。
..。什么时候该用..。
当您有特定需求时,最重要的是编写自己的泛型容器时。
https://stackoverflow.com/questions/31358804
复制相似问题