标签: allocator

c ++ Vector,每当它在堆栈上扩展/重新分配时会发生什么?

我是C++的新手,我在项目中使用了矢量类.我发现它非常有用,因为我可以有一个数组,只要有必要就会自动重新分配(例如,如果我想推送一个项目并且向量已达到它的最大容量,它会重新分配自己,为操作系统提供更多的内存空间),所以对向量元素的访问非常快(它不像列表,要达到"第n"元素,我必须通过"n"个第一个元素).

我发现这个问题非常有用,因为当我想将我的向量存储在堆/堆栈上时,他们的答案完全解释了"内存分配器"是如何工作的:

[1] vector<Type> vect;
[2] vector<Type> *vect = new vector<Type>;
[3] vector<Type*> vect;
Run Code Online (Sandbox Code Playgroud)

然而,怀疑是困扰我一段时间,我找不到它的答案:每当我构建一个向量并开始推入大量项目时,它将达到向量将满的时刻,因此继续增长它需要重新分配,将自身复制到一个新位置,然后继续push_back项(显然,这个重新分配它隐藏在类的实现上,所以它对我来说是完全透明的)

好吧,如果我在堆上创建了向量[2],我没有想象可能发生的事情:类向量调用malloc,获取新空间然后将自身复制到新内存中,最后删除调用free的旧内存.

然而,当我在堆栈上构造一个向量时,面纱会隐藏正在发生的事情[1]:当向量必须重新分配时会发生什么?AFAIK,无论何时在C/C++上输入一个新函数,计算机都会查看变量声明,然后展开堆栈以获得放置这些变量所需的空间,但是当你在堆栈中分配更多空间时功能已在运行.类向量如何解决这个问题?

c++ stack vector allocator

12
推荐指数
3
解决办法
8856
查看次数

从std :: vector接管内存

我使用外部库来处理大量数据.数据由原始指针传入,加上长度.该库不声明指针的所有权,但在完成数据时调用提供的回调函数(具有相同的两个参数).

通过使用方便地准备数据std::vector<T>,我宁愿不放弃这种便利.复制数据是完全不可能的.因此,我需要一种方法来"接管"一个拥有的内存缓冲区std::vector<T>,并且(稍后)在回调中释放它.

我目前的解决方案如下:

std::vector<T> input = prepare_input();
T * data = input.data();
size_t size = input.size();
// move the vector to "raw" storage, to prevent deallocation
alignas(std::vector<T>) char temp[sizeof(std::vector<T>)];
new (temp) std::vector<T>(std::move(input));
// invoke the library
lib::startProcesing(data, size);
Run Code Online (Sandbox Code Playgroud)

并且,在回调函数中:

void callback(T * data, size_t size) {
    std::allocator<T>().deallocate(data, size);
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案有效,因为标准分配器的deallocate函数忽略了它的第二个参数(元素计数)并且只是调用::operator delete(data).如果没有,可能会发生坏事,因为size输入向量可能比它小得多capacity.

我的问题是:是否有一种可靠的(以及C++标准)接管缓冲区std::vector并在以后"手动"释放它的方式?

c++ stdvector allocator c++11

12
推荐指数
1
解决办法
2430
查看次数

Stephen Lavavej的Mallocator在C++ 11中是一样的吗?

8年前,Stephen Lavavej发表了这篇博客文章,其中包含一个名为"Mallocator"的简单分配器实现.从那时起,我们已经过渡到C++ 11时代(很快就会出现C++ 17)......新的语言特征和规则是否会影响Mallocator,或者它仍然是相关的?

c++ containers allocator c++-standard-library c++11

12
推荐指数
1
解决办法
2009
查看次数

编译器支持STL容器中的有状态分配器

新的C++ 11标准要求STL实现支持容器中的有状态分配器.主STL实现(Visual Studio 2008,2010,libstdc ++)现在是否符合此要求?我在MSDN或libstdc ++文档中没有发现任何相关信息.

c++ containers stl allocator c++11

11
推荐指数
1
解决办法
2184
查看次数

为什么c ++中的allocator需要一个拷贝构造函数?

据说这里,这是因为异常规范的.我不明白.这个问题与异常规范有什么关系吗?

c++ stl allocator

11
推荐指数
1
解决办法
2157
查看次数

是否有一个C++分配器尊重被覆盖的新/删除?

我正在为类型数组实现资源分配克隆操作T.直接实现后使用从源到新数组new T[sz]std::copy调用.它走两次记忆.

我想分配原始内存然后使用,std::uninitialized_copy所以出于性能原因我只会走一次内存.我知道如何在使用自定义分配器(Allocator.allocate后跟std::uninitialized_copy)时完成此操作,并且我知道如何使用std::allocator(在规范的第20.4.1.1节中使用::operator new以下内容lib.allocator.members).我担心的是,std::allocator对于已经定义的类型T,基于a 的方法似乎是错误的T::operator new.我知道我可以使用Boost.TypeTraits来检测这种情况has_new_operator.

是否有一种简单的,符合标准的方式来分配并初始化原始内存,以一种尊重被覆盖的新方式(并且仅仅通过内存一次)?如果没有,使用SFINAE在一个实现使用std::allocator和一个使用被覆盖的运算符new 之间调度似乎是合理的吗?FWIW,通过Boost进行掠夺并没有显示出这种特性的使用has_new_operator.

谢谢,里斯

c++ new-operator allocator

11
推荐指数
1
解决办法
481
查看次数

C++中的高效数组重新分配

如何有效地调整使用符合标准的C++分配器分配的数组的大小?我知道在C++ alloctor界面中没有提供重新分配的工具,但是C++ 11版本是否使我们能够更容易地使用它们?假设我有一个定义vec了复制赋值运算符的类foo& operator=(const foo& x).如果x.size() > this->size(),我被迫

  1. 在内部存储的所有元素上调用allocator.destroy()foo.
  2. 在内部存储上调用allocator.deallocate() foo.
  3. 重新分配一个具有足够空间的新缓冲区x.size().
  4. 使用std :: uninitialized_copy填充存储.

有没有什么方法可以让我更轻松地重新分配内部存储而foo无需经历所有这些?如果您认为它有用,我可以提供一个实际的代码示例,但我觉得这里没有必要.

c++ memory-management allocator

11
推荐指数
1
解决办法
1566
查看次数

快速移动任务与Howard Hinnant的short_alloc

我正在使用Howard Hinnant很好的基于竞技场的小分配器,short_alloc.

让我感到震惊的是,从一个已经超出其竞技场并因此在堆上分配的向量进行移动分配可以使用通常的快速移动分配(即,抓取目标的资源)来完成.然而,这种情况并非如此:

typedef arena<16>                     arena_type;
typedef short_alloc<int, 16>          alloc_type;
typedef std::vector<int, alloc_type>  vec_type;

arena_type arena1, arena2;
vec_type vec1(alloc_type(arena1)), vec2(alloc_type(arena2));
vec1.resize(100);

void* data = vec1.data();
vec2 = std::move(vec1);
assert(vec2.data() == data);  // fails
Run Code Online (Sandbox Code Playgroud)

正如在这个答案中所解释的,这是由于向量的移动赋值运算符比较了两个分配器(注意propagate_on_container_move_assignment就是这样std::false_type).由于两个分配器不比较相等(因为它们具有不同的竞技场),目标向量需要分配内存并逐个移动值.

通过将等于运算符更改为,可以实现所需的行为

template <class T1, size_t N1, class T2, size_t N2>
bool operator==(const short_alloc<T1, N1>& x, const short_alloc<T2, N2>& y) noexcept
{
    return N1 == N2 && (&x.a_ == &y.a_ || y.a_.on_heap());
}
Run Code Online (Sandbox Code Playgroud)

其中,on_heap()如果分配没有使用它的竞技场检查.

这个解决方案看起来相当hackish(注意例如,平等不对称),我可以/我会通过这样做射击自己吗?有优雅的解决方案吗?

c++ memory-management allocator move-semantics c++11

11
推荐指数
1
解决办法
476
查看次数

容器优化:为什么STL容器方法参数不再使用allocator :: const_reference typedef?

在你阅读之前: const_reference是typedef,不需要const T&像你看到的那样std::vector<bool>::const_reference = bool.请在阅读其他内容时牢记这一点,以便正确理解它(如值得一提的,这对很多人来说很难).


我想将STL容器用于简单类型(例如int)并发现它们使用次优的const T& "反模式" - 它适用于大类,但对于简单/基本类型而言,如果不内联则是次优的 - 考虑嵌入式系统,例如在ARM/ATSAM4L上,具有实例化.

问题是:为什么例如从C++ 11开始vector::push_back重新设计参数(const value_type&)而不是(Allocator::const_reference)?对于泛型应该是相同的allocator,但是以另一种方式执行它将帮助我为基本类型编写自定义分配器(或模板特化),这将定义const_reference为类型本身(请参阅参考资料vector<bool>::const_reference = bool).

问题2:是否有适合我的适配器类?

像这样的东西:

template<class T, class base = std::vector<T> >
  class myvect: protected base {
public:
    typedef T const_reference;
    void push_back(const_reference value) {
        base::push_back(value); }}
Run Code Online (Sandbox Code Playgroud)

最终用法将是这样的:

typedef void (*action_t)(void*,int);
extern "C" void work(void *, action_t);
work(&vect, (action_t)&vect::push_back);
Run Code Online (Sandbox Code Playgroud)

(注意:忽略以前代码块中可能存在的转换问题,希望你有这个想法.) …

c++ containers stl allocator c++11

11
推荐指数
1
解决办法
1760
查看次数

C++ 11有状态分配器是否可以跨类型边界互换?

我的问题基本上是跟进:

考虑到复制构造的要求,如何在C++ 11中编写有状态分配器?

基本上,尽管C++ 11标准现在允许有状态分配器,但我们仍然要求如果复制某个Allocator,则副本必须通过==运算符与原始值进行比较.这表明副本可以安全地释放由原始分配的内存,反之亦然.

因此,这样就可以禁止分配器维护独特的内部状态,例如slab-allocator或内存池等等.一种解决方案是使用shared_ptr指针实现习惯用于内部状态,以便某些原始的所有副本Allocator使用相同的底层内存池.那不算太糟糕.除了...

根据上面提到的问题,以及接受的答案,标准似乎需要Allocator<T>具有可互操作的拷贝构造函数Allocator<U>,因此:

Allocator<T> alloc1;
Allocator<U> alloc2(alloc1);
assert(alloc1 == alloc2); // must hold true
Run Code Online (Sandbox Code Playgroud)

换句话说,无论模板参数如何,分配器类型都必须是可互操作的.这意味着如果我使用分配一些内存Allocator<T>,我必须能够使用Allocator<U>从原始构造的实例释放该内存Allocator<T>.

...这对于任何尝试编写使用某种基于大小的内存池的分配器来说都是一个显示阻塞,就像simple_segregated_storage池只返回基于某个大小的块一样sizeof(T).

但是......这是真的吗?

我意识到需要可互操作的复制构造函数,Allocator<T>::rebind因此容器的用户不需要知道say的内部细节,链接列表节点类型等.但据我所看到的,标准本身似乎并没有说什么,以便严厉作为一个要求Allocator<U>构建从Allocator<T>一定原文比较平等Allocator<T>的实例.

该标准基本上需要以下语义,其中X是类型Allocator<T>,a1a2X的实例,Y是类型Allocator<U>,b是实例Allocator<U>.

来自: …

c++ allocator c++11

11
推荐指数
1
解决办法
889
查看次数