我正在尝试编写一个四叉树稀疏矩阵类.简而言之,quadtree_matrix<T>或者是零矩阵或者四元(ne, nw, se, sw)的quadtree_matrix<T>.
我想最终测试不同的分配方案,因为这可能会影响线性代数运算的性能.所以我还将模板化quadtree_matrix标准分配器类型,以便我可以重用现有的分配器.
我将不得不分配两种不同类型的数据:a T或a node,包含四个指针(T或节点).对于我将考虑的所有算法,我知道可以期待什么样的数据,因为我知道在算法的任何一点上我面临的子矩阵的大小(我甚至不需要存储这些大小).
我当然会使用两个不同的分配器:这是可以的,因为分配器类型提供rebind模板和模板复制构造函数(并且旨在用作值类型,因为get_allocator标准容器的成员通过返回副本来建议).
问题是分配器成员函数使用某种pointer类型,这不需要是一个vanilla指针.一些分配器(boost进程间分配器)广泛使用此功能.
如果分配器指针类型是花园种类指针,我将没有问题:至少,我可以使用指针void并将它们重新解释为正确的类型(node*或者T*).我也可以使用联盟(可能更好).
据我所知,对allocator::pointer类型的POD没有要求.它们只需要是随机访问迭代器.
现在,我的问题是:
给定一个allocator类模板A<T>(或其等价物A::rebind<T>::other),是否有任何保证:
A<T>::pointer转换的能力是一个可访问的基础?A<U>::pointerUTA<T>::pointer,以A<U>::pointer提供T为的可接近碱U和"运行时类型"(无论这意味着在这种情况下)的castee是U?A<void>::pointer(如果这是有道理的)?或者我的问题是否有解决方案?
我想设计一个类模板,它采用分配器类型(在标准部分17.6.3.5中定义)作为模板参数.我看到如何使用默认设置来std::allocator_traits<A>填充任何缺少的成员A.除此之外,标准库或增强中是否有任何东西可以帮助正确使用分配器?
特别是:
为了尊重typedef std::allocator_traits<A>::propagate_on_container_copy_assignment,我是否必须在具有类型成员的每个类的特殊成员函数中检查这些内容A?或者是否有一些我可以用作成员的包装类型来代替它来处理这些东西?
如果我想通过在用户可见对象旁边存储额外数据来进行全面分配以减少分配数量,那么重新绑定分配器是否合适呢?
.
template<typename T, typename A>
class MyClass
{
private:
//...
struct storage {
int m_special_data;
T m_obj;
};
typedef typename std::allocator_traits<A>::template rebind_alloc<storage>
storage_alloc;
typedef typename std::allocator_traits<A>::template rebind_traits<storage>
storage_traits;
storage_alloc m_alloc;
static T* alloc(T&& obj)
{
storage_traits::pointer sp = storage_traits::allocate(m_alloc, 1);
sp->m_special_data = 69105;
return ::new(&sp->m_obj) T(std::move(obj));
}
//...
};
Run Code Online (Sandbox Code Playgroud) std::allocator的construct和destroy成员函数上构造元素的类型参数化:
template<class T>
class allocator
{
public:
typedef T value_type;
typedef T* pointer;
template<class U, class... Args>
void construct(U *p, Args&&... args);
template<class U>
void destroy(U *p);
...
};
Run Code Online (Sandbox Code Playgroud)
这是什么理由?为什么他们不采取value_type*或pointer?似乎allocator<T>应该只知道如何构造或销毁类型的对象T.
STL中是否有基于malloc/free的分配器?如果没有,有没有人知道一个简单的复制/粘贴?我需要它为一个不能调用new/delete的地图.
我在阅读为什么C++分配器中没有重新分配功能?和是否有可能创建在运行时堆的数组,然后在需要时分配更多的空间?,这清楚地表明动态数组对象的重新分配是不可能的.
但是,在Josuttis 的C++标准库中,它声明了一个Allocator,它allocator具有一个allocate具有以下语法的函数
pointer allocator::allocate(size_type num, allocator<void>::pointer hint = 0)
Run Code Online (Sandbox Code Playgroud)
其中hint有一个实现定义的含义,可用于帮助提高性能.
有没有利用这个的实现?
如何std::list分配保存next/ prev指针的节点及其T包含的元素?
我认为标准分配器只能用于为一种类型std::allocator::allocate分配内存(因为以递增的方式分配内存sizeof(T)).因此,似乎不可能在单个分配中分配列表节点和包含的对象,这意味着必须使用实现决定的任何方式分配节点,并且节点存储指向对象而不是对象本身的指针,这意味着两个级别的间接从指向列表节点的指针到它包含的对象,这似乎是低效的.是这样的吗?
在大约十年前的一个项目中,我们发现std::vector动态分配导致了严重的性能损失.在这种情况下,它分配了许多小向量,因此快速解决方案是编写一个类似于向量的类,包装在基于堆栈的预分配char数组中,用作其容量的原始存储.结果是static_vector<typename T, std::size_t Max>.如果您了解一些基础知识,这样的事情很容易写,你可以在网上找到很多这样的野兽.事实上,现在也有一个提升.
现在在嵌入式平台上工作,我们碰巧需要一个static_basic_string.这将是一个字符串,它预先在堆栈上分配固定的最大内存量,并将其用作容量.
起初我认为这应该相当容易(static_vector毕竟它可以基于现有的),但再看看std::basic_string界面我不再那么肯定了.它比std::vector界面更复杂.特别是实现find()功能系列std::basic_string不仅仅是一项繁琐的工作.
这让我再次思考.毕竟,这就是创建分配器的原因:基于new和delete使用其他方法替换分配.但是,要说分配器接口不实用将是轻描淡写.有一些文章在那里解释它,但有一个原因,我在过去的15年中看到这么少的本土分配器.
所以这是我的问题:
如果你必须实现一个basic_string相似的,你会怎么做?
static_basic_string?std::basic_string?与往常一样,对我们来说存在相当重要的限制:在嵌入式平台上,我们与GCC 4.1.2绑定,因此我们只能使用C++ 03,TR1和boost 1.52.
"经典"STL容器例如std::vector并将std::map其分配器类型作为模板参数.这意味着,std::vector<T, std::allocator<T>>和std::vector<T, MyAllocator>例如被视为完全独立的类型.
一些较新的分配感知类,如std::shared_ptr和std::tuple,另一方面利用类型擦除约分配器"隐藏"的信息,所以它不会形成类型签名的一部分.但是,std::unordered_map(具有类似的年份shared_ptr)保持了采用额外默认模板参数的经典方法.
问题:
处理std::vector<T, std::allocator<T>>和std::vector<T, MyAllocator>作为不同类型被认为是可取的,还是只是在STL编写时类型擦除的副作用不是众所周知的技术?
以这种方式使用类型擦除有哪些缺点(如果有的话)?
类型擦除的分配器是否总是首选新容器?
我想找到一种方法来存储几个std::vectors,每个都是一个不同但已知且相当小的大小,在连续的内存中.我意识到我可以编写自己的类,比如一个非常大的数组,并指向更大数组中数组的每个子部分的开头,就像一个单独的实体一样,但似乎应该有一个更聪明的方法来做到这一点.
有没有办法使用allocators,例如,创建连续std::vectors?我不想重新发明轮子只是因为我希望这种记忆局部性正常std::vectors
我不知道如何开始编码.我需要创建一个分配器,它接受一个指向内存的指针,在那里分配一个向量,然后以某种方式传回该向量结尾的地址,这样下一个std::vector分配器就可以抓住它并再次执行它.如何allocator返回一个值?
我目前正致力于编写池分配器.我的问题归结为以下代码:
template <typename T>
union myUnion {
T data;
myUnion<T>* nextUnion;
};
void someFunction(){
myUnion<T> mu;
T* t = new (std::addressof(mu.data)) T();
//some code
myUnion<T>* mu2 = reinterpret_cast<myUnion<T>*>(t);
}
Run Code Online (Sandbox Code Playgroud)
mu的地址是否与mu2相同?
allocator ×10
c++ ×10
c++11 ×2
stl ×2
allocation ×1
arrays ×1
stdlist ×1
string ×1
type-erasure ×1
vector ×1