该标准规定,在移动和重新绑定方面,分配器必须与其副本相同。但是,在调用其成员函数之后(例如分配值之后),它是否会变得与之前的状态不相等?也就是说,这可能是一个合规的分配器吗?
auto allocator_copy = allocator;
std::cout << (allocator == allocator_copy) << std::endl; // Outputs "1", as prescribed by the standard.
allocator.allocate(1);
std::cout << (allocator == allocator_copy) << std::endl; // Outputs "0";
Run Code Online (Sandbox Code Playgroud) std::allocatorC++ 中的默认类是无状态的。这意味着任何实例都std::allocator可以释放另一个实例分配的内存std::allocator。那么使用分配器实例来分配内存有什么意义呢?
例如,为什么内存分配是这样的:
allocator<T> alloc, alloc2;
T* buffer = alloc.allocate(42);
alloc2.deallocate(buffer);
Run Code Online (Sandbox Code Playgroud)
当函数可以轻松完成相同的工作时:
T* buffer = allocate(42);
deallocate(buffer);
Run Code Online (Sandbox Code Playgroud) 我正在使用自定义分配器来计算几个容器中的内存使用情况.目前我使用静态变量来计算内存使用量.如何在不必重写分配器以使用不同的静态变量的情况下将此帐户分隔到多个容器中?
static size_t allocated = 0;
template <class T>
class accounting_allocator {
public:
// type definitions
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//static size_t allocated;
// rebind allocator to type U
template <class U>
struct rebind {
typedef accounting_allocator<U> other;
};
// return address of values
pointer address (reference value) const {
return &value;
}
const_pointer address (const_reference value) const {
return &value; …Run Code Online (Sandbox Code Playgroud) 我在http://msdn.microsoft.com/en-us/library/ee292117.aspx和http://msdn.microsoft.com/en-us/library/ee292134.aspx上看到Microsoft为专门提供的宏和类分配器,但我不确定每个缓存策略是什么,如何使用它们.有人可以解释何时使用这些部件?
cache_freelist- cache_freelist模板类维护一个大小的内存块的空闲列表Sz.当空闲列表已满时,它用于operator delete释放内存块.当空闲列表为空时,它用于operator new分配新的内存块.空闲列表的最大大小由参数中max class传递的类确定Max.每个存储块保持Sz可用存储器的字节并且数据operator new和operator delete需要.cache_suballoc- cache_suballoc模板类将释放的内存块存储在具有无限长度的空闲列表中,使用freelist<sizeof(Type), max_unbounded>和子分配来自operator new空闲列表为空时分配的较大块的内存块.每个块都包含Sz * Nelts可用内存的字节operator new和operator delete需要的数据.从未释放分配的块.cache_chunklist- 此模板类用于operator new分配原始内存块,子分配块以在需要时为内存块分配存储空间; 它将释放的内存块存储在每个块的单独空闲列表中,并用于operator delete在没有任何内存块被使用时释放块.每个内存块保存Sz可用内存的字节和指向它所属的块的指针.每个块都包含Nelts内存块,三个指针,一个int operator new以及operator delete需要的数据.我自己写了几个分配器,但是这个文档只是......令人困惑.
X:我需要知道我的程序的每个部分使用了多少内存.我的程序使用了很多C++ std库.特别是,我想知道每个对象使用多少内存.
我是怎么做的:记录消费some_vector,只写
my::vector<double,MPLLIBS_STRING("some_vector")> some_vector;
Run Code Online (Sandbox Code Playgroud)
哪里
namespace my {
template<class T, class S>
using vector = std::vector<T,LoggingAllocator<T,S>>;
}
Run Code Online (Sandbox Code Playgroud)
loggin分配器实现如下:
template<class T, class S = MPLLIBS_STRING("unknown")> struct LoggingAllocator {
// ... boilerplate ...
pointer allocate (size_type n, std::allocator<void>::const_pointer hint = 0) {
log_allocation(boost::mpl::c_str<S>::value);
// allocate_memory (I need to handle it myself)
}
void destroy (pointer p) ; // logs destruction
void deallocate (pointer p, size_type num); // logs deallocation
};
Run Code Online (Sandbox Code Playgroud)
问题:是否有更好的方法以通用方式获得此行为?通过更好,我的意思是,更简单,更好,没有依赖boost::mpl和mpllibs::metaparse,... ...理想情况下,我只想写 …
假设我有100G整数,并希望将它们插入到vector<int>32位机器上,是否可能?
如果我使用自定义allocator来管理存储策略,那么如何保证以下操作始终有效:
vector<int> coll;
coll.insert(100G integers);
memcpy(coll.begin() + (1024 * 1024 * 1024 * 8), "Hello", 5);
Run Code Online (Sandbox Code Playgroud)
请注意,C++标准要求存储在a中的对象vector必须是连续的.coll.begin() + (1024 * 1024 * 1024 * 8)可能是硬盘的地址.
标准没有说明分配器,std::vector但只需要分配器来满足这个Allocator概念.没有关于allocator的value_type,没有reference_type,没有任何内容.
我认为std::vector<T, A>内部重新绑定A到分配器T,所以我给了一个向量std::allocator<char>,它按预期工作.
但是,如果std::allocator<void>给出GCC会产生错误,如下所示:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/ext/alloc_traits.h: In instantiation of ‘struct __gnu_cxx::__alloc_traits<std::allocator<void> >’:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/bits/stl_vector.h:75:28: required from ‘struct std::_Vector_base<int, std::allocator<void> >’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/bits/stl_vector.h:214:11: required from ‘class std::vector<int, std::allocator<void> >’
a.cpp:5:42: required from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/ext/alloc_traits.h:109:53: error: forming reference to void
typedef value_type& reference;
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/ext/alloc_traits.h:110:53: error: forming reference to void
typedef const value_type& const_reference;
^
Run Code Online (Sandbox Code Playgroud)
这是GCC的错误吗?还是我误读标准?
我正在尝试实现一个STL样式的容器类,我有一个关于在我的类中使用allocator的问题:
STL中静态成员函数的用途是什么allocator_traits?
到现在为止,我认为我应该实例化allocator_type(可能通过某种空基础优化来改善内存占用).因此,我最终会得到这样的结论:
struct EmptyBaseOpt : allocator_type
{
EmptyBaseOpt(const allocator_type & a, allocator_type::const_pointer p)
: allocator_type(a), prefix_ptr(p) { }
allocator_type::pointer prefix_ptr;
}
EmptyBaseOpt ebo;
Run Code Online (Sandbox Code Playgroud)
然后,我可以通过以下方式使用分配器:
allocator_type & alloc = ebo;
alloc.allocate(100, ebo.prefix_ptr);
Run Code Online (Sandbox Code Playgroud)
另一方面,allocator_traits在C++ 11中似乎意味着以下用法:
std::allocator_traits<allocator_type>::allocate(100, ebo.prefix_ptr);
Run Code Online (Sandbox Code Playgroud)
我想这个静态allocate成员函数可能会allocator_type通过其默认构造函数创建一个临时的临时实例.但这导致了以下问题:
如果allocator_type是有状态分配器会发生什么?如果我使用静态成员函数allocator_traits而不是从一个实例中调用非静态方法,这样的分配器是否能够保持其状态allocator_type?
allocator_type如果我可以直接使用静态成员函数,为什么我要实例化并烦恼像EBO这样的东西allocator_traits呢?
如前所述,我的理解是,任何类类模板参数都应该在我的容器类中实例化,以便允许这些参数的有状态版本.这种理解是否正确,它如何适应静态成员函数allocator_traits?
std::allocator_traits 当我提供一个具有单个模板参数的分配器的STL样式容器时,它会自动运行它的魔法,但是当我提供一个STL样式的容器时,它没有一个具有两个模板参数但其他类似的分配器.
std::allocator_traits如何与具有多个模板参数的分配器进行交互,我需要做什么?std::allocator_traits在这种情况下是否可以提供合理的默认值?
作为一个例子,如果我采用简单的分配器Howard Hinnant在Allocator Boilerplate中提供并将其提供给std::vector<>那么一切都很好.如果我int向allocator模板添加一个虚拟参数(并根据需要进行轻微修改),那么我会遇到编译器错误,因为编译器无法找到rebind其他内容.
这是代码中的描述:
http://coliru.stacked-crooked.com/a/173c57264137a351
如果我必须std::allocator_traits在这种情况下专注自己,有没有办法仍然获得默认值?
例如,来自std :: deque :: operator = in C++ Reference:
(1)Copy Assignment (const std :: deque&other)
用其他内容的副本替换内容.
如果std :: allocator_traits :: propagate_on_container_copy_assignment()为true,则目标分配器将替换为源分配器的副本.如果目标和源分配器不比较相等,则使用目标(*this)分配器来释放内存,然后在复制元素之前使用其他分配器来分配它.
如果this->get_allocator() == other.get_allocator(),我可以简单地破坏和释放this,如果需要'元素,或分配,如果需要构建元素,或复制分配的元素other来*this如果需要的话.
但如果不是呢?上面的引用是否意味着我不能复制 - 分配元素,所以我必须首先销毁和释放所有元素,使用this->get_allocator(),然后分配和构造元素,使用other.get_allocator()?
但如果是这种情况,我为什么要other.get_allocator()用于分配呢?
以后不会导致一些运行时错误,因为this不会正确释放内存吗?
(2)移动作业 (std :: deque && other)
使用移动语义替换其他内容(即其他数据从其他数据移动到此容器中).其他是后来处于有效但未指定的状态.如果std :: allocator_traits :: propagate_on_container_move_assignment()为true,则目标分配器将替换为源分配器的副本.如果它为假并且源和目标分配器不比较相等,则目标不能获取源存储器的所有权,并且必须单独移动 - 分配每个元素,根据需要使用其自己的分配器分配额外的存储器.在任何情况下,*this中最初存在的所有元素要么被销毁,要么被元素移动赋值替换.
如果this->get_allocator() == other.get_allocator(),这是一项简单的任务.
但如果没有,则上面会出现同样的问题,除非在这种情况下使用移动分配.
在这两种情况下,我还有一个问题.
如果元素既不能复制分配也不能移动分配,是否可以销毁它并从其他元素构建?如果是,我应该使用谁的分配器?