- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我最近遇到了 Howard Hinnant 的 short_alloc这是我见过的自定义分配器的最佳示例。
但是当我花更多时间研究代码以将其集成到我的个人项目中时,我突然想到提供基于堆栈的分配的 arena
类可能并不总是返回正确对齐的内存.实际上,我担心只有第一次分配才能保证适当对齐(因为缓冲区本身具有强制对齐),请参见下面的相关代码片段:
template <std::size_t N>
class arena
{
static const std::size_t alignment = 16;
alignas(alignment) char buf_[N];
char* ptr_;
//...
};
template <std::size_t N>
char*
arena<N>::allocate(std::size_t n)
{
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
if (buf_ + N - ptr_ >= n)
{
char* r = ptr_;
ptr_ += n;
return r;
}
return static_cast<char*>(::operator new(n));
}
我可以想出几种方法来解决这个问题(以浪费一些内存为代价),最简单的方法是在 allocate/deallocate
函数中舍入 size
为 alignment
的倍数。
但在更改任何内容之前,我想确保我在这里没有遗漏任何东西......
最佳答案
这段代码是在我拥有 std::max_align_t
之前编写的在我的工具箱中(现在位于 <cstddef>
中)。我现在可以这样写:
static const std::size_t alignment = alignof(std::max_align_t);
在我的系统上,它与当前代码完全相同,但现在更便携。这是 new
的对齐方式和 malloc
保证返回。一旦你有了这个“最大对齐”的缓冲区,你就可以在其中放入任何一种类型的数组。但是你不能使用相同的arena
对于不同的类型(至少不是具有不同对齐要求的不同类型)。出于这个原因,也许最好使用模板 arena
在第二个 size_t
,等于 alignof(T)
.这样你就可以防止同样的arena
避免被具有不同对齐要求的类型意外使用:
arena<N, alignof(T)>& a_;
假设每个分配来自 arena
具有相同的对齐要求,并且假设缓冲区最大对齐,那么缓冲区中的每个分配都将针对 T
进行适当对齐.
例如在我的系统上alignof(std::max_align_t) == 16
.具有这种对齐方式的缓冲区可以保存以下数组:
alignof == 1
.alignof == 2
.alignof == 4
.alignof == 8
.alignof == 16
.由于某些环境可能支持具有“ super 对齐”要求的类型,因此需要添加额外的安全预防措施(例如在 short_alloc
内):
static_assert(alignof(T) <= alignof(std::max_align_t), "");
如果你是 super 偏执狂,你也可以检查一下 alignof(T)
是 2 的幂,尽管 C++ 标准本身保证这将始终为真 ([basic.align]/p4)。
更新
我仔细研究了这个问题,并认为将请求的分配大小四舍五入到下一个 alignment
(正如OP所建议的)是最好的解决方案。我更新了"short_alloc"在我的网站上执行此操作。
template <std::size_t N>
char*
arena<N>::allocate(std::size_t n)
{
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
n = align_up(n);
if (buf_ + N - ptr_ >= n)
{
char* r = ptr_;
ptr_ += n;
return r;
}
return static_cast<char*>(::operator new(n));
}
对于您知道不需要最大对齐分配的特殊情况(例如 vector<unsigned char>
),可以简单地调整 alignment
适本地。也可以有short_alloc::allocate
通过alignof(T)
至arena::allocate
和 assert(requested_align <= alignment)
template <std::size_t N>
char*
arena<N>::allocate(std::size_t n, std::size_t requested_align)
{
assert(requested_align <= alignment);
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
n = align_up(n);
if (buf_ + N - ptr_ >= n)
{
char* r = ptr_;
ptr_ += n;
return r;
}
return static_cast<char*>(::operator new(n));
}
这会让您确信,如果您调整了 alignment
向下,你没有向下调整太多。
再次更新!
我已更新 description和 code由于这个出色的问题(我多年来一直忽略此代码),因此对这个分配器的影响很大。
之前更新中提到的对齐检查现在在编译时完成(编译时错误总是优于运行时错误,甚至是断言)。
arena
和 short_alloc
现在在对齐上进行了模板化,以便您可以轻松自定义您预期的对齐要求(如果您猜得太低,它会在编译时被捕获)。该模板参数默认为alignof(std::max_align_t)
.
arena::allocate
函数现在看起来像:
template <std::size_t N, std::size_t alignment>
template <std::size_t ReqAlign>
char*
arena<N, alignment>::allocate(std::size_t n)
{
static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
auto const aligned_n = align_up(n);
if (buf_ + N - ptr_ >= aligned_n)
{
char* r = ptr_;
ptr_ += aligned_n;
return r;
}
return static_cast<char*>(::operator new(n));
}
感谢别名模板,这个分配器比以往更容易使用。例如:
// Create a vector<T> template with a small buffer of 200 bytes.
// Note for vector it is possible to reduce the alignment requirements
// down to alignof(T) because vector doesn't allocate anything but T's.
// And if we're wrong about that guess, it is a comple-time error, not
// a run time error.
template <class T, std::size_t BufSize = 200>
using SmallVector = std::vector<T, short_alloc<T, BufSize, alignof(T)>>;
// Create the stack-based arena from which to allocate
SmallVector<int>::allocator_type::arena_type a;
// Create the vector which uses that arena.
SmallVector<int> v{a};
这不一定是此类分配器的最终决定。但希望这是您构建自定义分配器的坚实基础。
关于c++ - Hinnant 的 short_alloc 和对齐保证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33722907/
我希望能够像在 jsFiddle 中那样将元素列表对齐到右侧的复选框。这是如何做到这一点的最佳实践?传统上我从来没有 float 过相互嵌套的元素,所以我想确定这是否是解决此问题的正确方法。 代码(h
指令.align n是什么意思在数组中做什么? 更具体地说,假设我有以下部分代码: array: .align 2 .space 800 它的重要性是什么,为什么不跳过它并使用
基本上我正在寻找一种强制特定相对对齐的方法 即我想保证其他一些值(value) m s.t m > n alignment_of(foo) % 2^m == 2^n IE: .align 2^m; .
在我的代码中,我必须考虑一个数组数组,其中内部数组具有固定维度。为了使用 STL 算法,将数据实际存储为数组的数组很有用,但我还需要将该数据传递给 C 库,该库采用扁平化的 C 样式数组。 如果能够以
横向上,我想显示两个位图,并在它们之间显示一个标签字段。 代码看起来很简单,但所有字段都添加在屏幕左侧。 HorizontalFieldManager hfm = new HorizontalFiel
我想绘制一个变量名称及其符号。因为某些变量的名称很长,所以我试图将换行符与轴标签混合使用。这会导致对齐中发生有趣的事情: par(mar=c(1,12,1,1)) plot( y=1:6, 1:6,
使用这个脚本 df <- data.frame(x = 1:5, y = 1:5, color = letters[1:5]) ggplot(df, aes(x, y, fill = color))
我有一个带有标量字段的结构,比如妈妈,我想在屏幕上对齐的列中显示结构的值,可能还有一些标题。这是一个最小的工作示例: mom.a = 1; mom.b = 2; mom.veryLongName =
在 iOS6 中,我使用自动布局。 我有 2 个以编程方式创建的 View v1 和 v2。 v2 作为 subview 添加到 v1 v1 的约束已通过编程方式创建(此处未显示)。 我希望 v1 和
概述 浏览时operator new, operator new[] - cppreference.com ,似乎我们有许多选项来分配具有特定对齐要求的对象数组。但是,没有指定如何使用它们,而且我似乎
Widget _createProfileContainer() { return new Container( height: 64.0, child: ne
我正在使用 Bootstrap 和语义 UI 的组合来设计和对齐我的网页。目前,我在将页面 api map 和博客文章在整个页面上对齐时遇到问题,而不是像图像所示 那样堆叠在一起。 这是我的底层代码,
所以我已经添加了标签和所有内容,但我仍然在格式化和对齐所有内容时遇到问题。计算按钮显然应该居中。我知道使用 gridbag 将框架分割成坐标系,当一列大于其他列时,它会调整其他列并将其抛弃(对吗?)。
我必须将程序上的按钮对齐到中间,我运行的当前代码但显示的按钮与程序一样大,我想要一个特定大小的中心按钮,这是我尝试过的 /** * Created by Timk9 on 11/04/2016.
我正在尝试将 VIM 作为我的 ruby/rails 编辑器。太胖了,我对它的功能印象深刻 并且我能够安装以下插件以提供更好的 IDE 体验 自动配对 Better-snipmate-snippe
在结构内对齐成员的最佳或常规方法是什么?添加虚拟数组是最佳解决方案吗? 我有一个 double 的结构和 double 的三倍是吗? struct particle{ double mass;
我正在尝试对齐我的输出,但由于某种原因我无法做到我多么想要它,这真的很令人沮丧。标题不会正确对齐。我不知道我是否正确使用了 setw()。 #include using std::cout; usi
我正在开发一个 android 应用程序,其相对布局如下所示。 这是应用程序在屏幕上的显示方式的 imgur 链接:http://imgur.com/c4rNJ .我希望“Text 1”出现在“a l
我不确定为什么我不能在下面的代码中调整按钮的位置。我有几行设置了边界,但我一定遗漏了一些东西。 public DayGUI() { mainFrame = new JF
我有一个 html 页面,我想在页面底部对齐一个 iframe,使 iframe 占据所有宽度,我无法在底部对齐 iframe。请找到底部的 iframe 标签页面。 The rest of th
我是一名优秀的程序员,十分优秀!