- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在使用 Howard Hinnant 的漂亮的基于竞技场的小分配器,short_alloc .
令我震惊的是,从 vector 进行的 move 分配可以使用通常的快速 move 分配(即获取目标的资源)来完成,该 vector 已经超出其 arena,因此分配在堆上。然而,事实并非如此:
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
如 this answer 中所述,这是由于 vector 的 move 赋值运算符比较了两个分配器(请注意 propagate_on_container_move_assignment
是 std::false_type
)。由于两个分配器比较不相等(因为它们有不同的领域),目标 vector 需要分配内存并一个一个地 move 值。
通过将相等运算符更改为来实现所需的行为
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());
}
其中 on_heap()
检查分配器是否未使用其 arena。
这个解决方案看起来很老套(例如,注意平等不是对称的),这样做我可以/会搬起石头砸自己的脚吗?有没有优雅的解决方案?
最佳答案
两个不同的 arena
对象可能有不同的生命周期。依赖于不同 arena
对象的两个不同 short_alloc
对象管理具有不同生命周期的内存。因此,具有不同 short_alloc 对象的两个 std::vector
对象不能简单地在它们之间 move 指针。
你的 hack 不会起作用,因为它是从 arena
或 new[]
分配的指针。您的黑客假设分配器成为大 vector 的堆分配器,但事实并非如此。如果不检查请求的大小或释放的指针,分配器就不知道这一点。
正确的解决方案是用 move 运算符替换分配器对象。为此,short_alloc
应该定义:
using propagate_on_container_move_assignment = std::true_type;
private:
arena_type * a_; // <--- instead of reference
public:
short_alloc(const short_alloc&) = default;
// !!! Don't delete the move assignment !!!
// short_alloc& operator=(const short_alloc&) = delete;
这将使 move 运算符按预期工作。 move 后它将开始使用另一个竞技场。
arena
的风险很高。
根据我提议的更改,风险系数略高。 arena
超出范围的问题现在也涉及到传递引用 vector 。当 arena
定义在内部 block 中时,arena
超出范围的问题也存在。
其他 arena
超出范围的行为可能会让程序员大吃一惊,并引入错误。这就是为什么我不喜欢这个解决方案。然而,有时人们愿意在时间关键部分编写危险代码(在分析和分析之后)。
short_alloc
分配器标记为
heap 分配器。它可以在使用
new[]
的第一次分配后立即以这种方式标记。这将适用于
std::vector
,因为它在方法调用之间只保留一 block 内存。尽管使用
std::vector
,但它与大多数其他容器不兼容,因为它们中的大多数都使用节点,例如
std::map
和
std::unordered_set
。
问题是一些节点来自 arena
而一些来自堆。使用建议的 operator==
如果使用 new[]
则返回 true
,从 std::map
将使来自不相关领域的一些节点 move 到目标 std::map
。非常出乎意料,而且是个坏主意。这将生成一个 std::map
对象,该对象包含来自其自己的 arena
和来自不相关的 arena
的节点。不相关的arena
的节点永远不会被std::map
释放。只有当它们分配的 arena
死亡时,这些坏节点才会被释放。
问题中提出的技术完全被破坏了。除了 std::vector
之外,它会以令人惊讶的方式导致几乎所有内容的分配不一致。我强烈反对。
关于c++ - 使用 Howard Hinnant 的 short_alloc 进行快速 move 分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19230283/
我正在使用内存有限的嵌入式系统。另外,所使用的工具链当前最多支持C++ 17。 我必须将UTC时间戳转换为本地时间戳,以便向用户显示数据。从另一个系统中检索应该使用的时区。所有这些都与Howard H
我正在使用 Howard Hinnant 的免费、开源、跨平台、C++11/14 时区库: #include "date/tz.h" #include int main() { std::c
我有一个像这样的日期字符串 YYYYMMDD HHMMSSFFF。我正在尝试使用 Howard Hinnats 日期库。代码片段是这样的, std::chrono::system_clock::tim
示例:从字符串解析日期/时间,然后我想分解日期/时间的组成部分。似乎我得到了所有内容,但我被困在小数秒上。代码如下 std::wistringstream in{ L"2016-12-11 15:43
我正在研究 C++ 中的特定实现。假设我有一个来自 Howard Hinnant's date library 的 date::year_month_day 变量称为 X 我想将其转换为 std::c
我有以下代码,使用日期库: #include "date.h" #include #include using namespace date; using namespace std::chron
这是a双重否定的Curry-Howard对应; (a -> r) -> r 或 (a -> ⊥) -> ⊥,或两者兼而有之? 这两种类型都可以在 Haskell 中编码如下,其中 ⊥ 编码为 fora
我正在尝试使用这个 C++ 日期 library计算特定日期自年初以来的天数。 我可以创建日期对象: date::year_month_day queryDate((date::year(2019))
我正在使用 Howard Hinnant 的漂亮的基于竞技场的小分配器,short_alloc . 令我震惊的是,从 vector 进行的 move 分配可以使用通常的快速 move 分配(即获取目标
我有以下玩具代码: #include "date/date.h" #include using namespace std; using namespace chrono; int main() {
我正在使用 Howard Hinnant 的日期 C++ 库 ( https://howardhinnant.github.io/date/date.html ),但我在使用它时遇到了一些困惑。下面是
我希望能够将自定义分配器与 std::vector 一起使用,以便将小数据缓冲区(例如,小于 1024 字节)存储在堆栈上,并且只有较长的 vector 存储在堆上。作为一个有 Fortran 背景的
问题是我尝试使用 day_point 时出现的错误,day_point 是与 Howard Hinnant 的 date.h 头文件一起使用的命令之一。头文件保存在正确的位置,并且到目前为止与所有其他
我是一名优秀的程序员,十分优秀!