我试图通过一些任意类型的数组实现一个在内存中跟随的类:
template<class T>
class Buf
{
size_t n;
int refs;
explicit Buf(size_t n) : n(n) { }
// other declarations are here as appropriate
// Followed in memory by:
// T items[n];
};
使用operator new
:
template<class T>
Buf<T> *make_buf(size_t n)
{
// Assume the caller will take care of constructing the array elements
return new(operator new(sizeof(Buf<T>) + sizeof(T) * n)) Buf<T>(n);
}
template<class T>
void free_buf(Buf<T> *p)
{
// Assume the caller has taken care of destroying the array elements
p->~Buf<T>();
return operator delete(p);
}
template<class T>
T *get_buf_array(Buf<T> *p)
{
return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + sizeof(Buf<T>));
}
但是现在,我如何使用符合标准的分配器 SomeAllocator
来实现这一点?
是否保证SomeAllocator::rebind<char>::other::allocate
将返回适合任何类型对象的内存?如果是这样,我是否可以安全地使用某种char类型的分配器?如果没有,我有任何替代方案,或者一般情况下分配器是否无法执行此任务? (在最坏的情况下,我想我可以将指针转换为uintptr_t
并手动对齐它们,但我想知道是否有更好的方法。)
答案 0 :(得分:1)
我在想解决方案可能是通过创建一个名义上的早期数组。
+-----------+
|Buf<T> |
+-------+---+---+-------+-------+
|T[0] | T[1] |T[2] | T[3]...
+-------+-------+-------+-------+
With the non-overlapping T[2], T[3], ... being the required array of T.
template<class T>
class Buf
{
size_t n;
int refs;
explicit Buf(size_t n) : n(n) { }
// other declarations are here as appropriate
// Followed in memory by:
// T items[n];
};
破坏元素的数量为: -
const size_t lead = ( sizeof(Buf<T>) + sizeof(T) - 1) / sizeof(T);
最后,我可以通过
访问i的原始内存(reinterpret_cast<T*>( this ) )[ i + lead ];
答案 1 :(得分:0)
我担心你对C ++标准的要求做出了无根据的假设。你想要做的事情可能不是一般的。
默认分配器(new或malloc)需要返回指向适合any complete object type with a fundamental alignment requirement
对齐的内存块的指针。大小必须为at least as large as the requested size
。自定义分配器有不同的要求,具体取决于它们分配的内容。不保证一种类型的分配器返回适合另一种类型的存储器。当然,如果你是实现自定义分配器的人,你可以确保它返回你需要的东西。
编译器需要满足一些关于内存布局的约束,但它不能保证在其他内容之后立即将某些内容放在内存中。可以插入填充字节以满足对齐要求。
最近的C ++标准为处理路线提供了相当多的支持。某处可能有你的答案。我怀疑这是你没有告诉我们的一些要求。也许还有另一种方法可以解决它。
答案 2 :(得分:0)
我认为符合标准的标准兼容分配器?由于您不需要将分配器与stl数据结构一起使用,因此即使您可以这样做,也没有必要满足它的要求,因为我认为它是一种巧妙的方法。在这种情况下,您可以使用带有自定义stl样式分配器的std :: vector作为模板参数来实现缓冲区。关于operator new和operator new []的对齐保证,我建议你看看:
Is there any guarantee of alignment of address return by C++'s new operation?
如果您的对齐问题适用于基本类型,例如双精度等,那么您可以在http://en.cppreference.com/w/cpp/memory/align中看到std :: align。
但是,如果您有更陌生/更大的对齐要求,例如将每个元素对齐到缓存行等,或者T是一个大小为sizeof(T)mod alignment!= 0的类型,则在分配T&#数组时可能会遇到问题39; S。在这种情况下,即使阵列的第一个元素对齐以满足要求,它也不意味着所有后续元素也将对齐。
答案 3 :(得分:0)
通过将分配器重新绑定到std::aligned_storage
的专业化来约束对齐。
typedef std::aligned_storage_t< 1, std::max( alignof (Buf<T>), alignof (T) ) >
unit_type; // lowest-common-denominator type for aligned allocation
std::size_t unit_count // number of unit_type array elements needed
= ( sizeof (Buf<T>) + sizeof (T) * n // = actual used storage
+ sizeof (unit_type) - 1 ) // + alignment padding
/ sizeof (unit_type); // divided by element size
typedef typename std::allocator_traits< SomeAllocator >::rebind_alloc< unit_type >
rebound;
rebound a( alloc_parm ); // Retain this somewhere if statefulness is allowed.
ptr = std::allocator_traits< rebound >::allocate( a, unit_count );
(请记住,所有分配器访问都通过allocator_traits
!)