- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我想知道有一个符合 C++ 标准的库是否可行 allocator
使用位于堆栈中的(固定大小的)缓冲区。
不知何故,这个问题似乎还没有在 SO 上这样问过,尽管它可能已经在其他地方得到了隐含的回答。
所以基本上,就我的搜索而言,似乎应该可以创建一个使用固定大小缓冲区的分配器。现在,乍一看,这应该意味着也应该可以有一个使用固定大小缓冲区的分配器,该缓冲区“存在于”堆栈中,但它确实出现,没有广泛的这种实现。
让我举一个例子来说明我的意思:
{ ...
char buf[512];
typedef ...hmm?... local_allocator; // should use buf
typedef std::basic_string<char, std::char_traits<char>, local_allocator> lstring;
lstring str; // string object of max. 512 char
}
StackAllocator
没有默认的构造函数——我在想
every allocator class needs a default ctor .
最佳答案
绝对有可能创建一个完全符合 C++11/C++14 的堆栈分配器*。但是您需要考虑有关堆栈分配的实现和语义以及它们如何与标准容器交互的一些后果。
这是一个完全符合 C++11/C++14 的堆栈分配器(也托管在我的 github 上):
#include <functional>
#include <memory>
template <class T, std::size_t N, class Allocator = std::allocator<T>>
class stack_allocator
{
public:
typedef typename std::allocator_traits<Allocator>::value_type value_type;
typedef typename std::allocator_traits<Allocator>::pointer pointer;
typedef typename std::allocator_traits<Allocator>::const_pointer const_pointer;
typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference;
typedef typename std::allocator_traits<Allocator>::size_type size_type;
typedef typename std::allocator_traits<Allocator>::difference_type difference_type;
typedef typename std::allocator_traits<Allocator>::const_void_pointer const_void_pointer;
typedef Allocator allocator_type;
public:
explicit stack_allocator(const allocator_type& alloc = allocator_type())
: m_allocator(alloc), m_begin(nullptr), m_end(nullptr), m_stack_pointer(nullptr)
{ }
explicit stack_allocator(pointer buffer, const allocator_type& alloc = allocator_type())
: m_allocator(alloc), m_begin(buffer), m_end(buffer + N),
m_stack_pointer(buffer)
{ }
template <class U>
stack_allocator(const stack_allocator<U, N, Allocator>& other)
: m_allocator(other.m_allocator), m_begin(other.m_begin), m_end(other.m_end),
m_stack_pointer(other.m_stack_pointer)
{ }
constexpr static size_type capacity()
{
return N;
}
pointer allocate(size_type n, const_void_pointer hint = const_void_pointer())
{
if (n <= size_type(std::distance(m_stack_pointer, m_end)))
{
pointer result = m_stack_pointer;
m_stack_pointer += n;
return result;
}
return m_allocator.allocate(n, hint);
}
void deallocate(pointer p, size_type n)
{
if (pointer_to_internal_buffer(p))
{
m_stack_pointer -= n;
}
else m_allocator.deallocate(p, n);
}
size_type max_size() const noexcept
{
return m_allocator.max_size();
}
template <class U, class... Args>
void construct(U* p, Args&&... args)
{
m_allocator.construct(p, std::forward<Args>(args)...);
}
template <class U>
void destroy(U* p)
{
m_allocator.destroy(p);
}
pointer address(reference x) const noexcept
{
if (pointer_to_internal_buffer(std::addressof(x)))
{
return std::addressof(x);
}
return m_allocator.address(x);
}
const_pointer address(const_reference x) const noexcept
{
if (pointer_to_internal_buffer(std::addressof(x)))
{
return std::addressof(x);
}
return m_allocator.address(x);
}
template <class U>
struct rebind { typedef stack_allocator<U, N, allocator_type> other; };
pointer buffer() const noexcept
{
return m_begin;
}
private:
bool pointer_to_internal_buffer(const_pointer p) const
{
return (!(std::less<const_pointer>()(p, m_begin)) && (std::less<const_pointer>()(p, m_end)));
}
allocator_type m_allocator;
pointer m_begin;
pointer m_end;
pointer m_stack_pointer;
};
template <class T1, std::size_t N, class Allocator, class T2>
bool operator == (const stack_allocator<T1, N, Allocator>& lhs,
const stack_allocator<T2, N, Allocator>& rhs) noexcept
{
return lhs.buffer() == rhs.buffer();
}
template <class T1, std::size_t N, class Allocator, class T2>
bool operator != (const stack_allocator<T1, N, Allocator>& lhs,
const stack_allocator<T2, N, Allocator>& rhs) noexcept
{
return !(lhs == rhs);
}
std::allocator<T>
)。
std::vector
(这将分配一个连续的内存块)如果使用得当,但不能用于
std::map
,它将以不同的顺序分配和释放节点对象。
std::vector
如果它首先从堆栈中分配单个连续块,然后分配第二个堆栈块,然后释放第一个块,则会导致未定义的行为,每次 vector 将其容量增加到仍然小于
stack_size
的值时都会发生这种情况。 .这就是您需要提前保留堆栈大小的原因。 (但请参阅下面有关 Howard Hinnant 实现的说明。)
malloc
),除了它从预先分配的堆栈缓冲区中提取而不是调用
sbrk
?如果是这样,您基本上是在谈论实现一个通用分配器,该分配器以某种方式维护内存块的空闲列表,只有用户可以为其提供预先存在的堆栈缓冲区。这是一个复杂得多的项目。 (如果空间用完了怎么办?抛出
std::bad_alloc
?退回到堆上?)
std::vector
,它将始终使用可以提前保留的单个连续缓冲区。当
std::vector
需要更大的缓冲区,它将分配更大的缓冲区,复制(或移动)较小缓冲区中的元素,然后释放较小的缓冲区。当 vector 请求更大的缓冲区时,上面的 stack_allocator 实现将简单地回退到辅助分配器(默认为
std::allocator
。)
const static std::size_t stack_size = 4;
int buffer[stack_size];
typedef stack_allocator<int, stack_size> allocator_type;
std::vector<int, allocator_type> vec((allocator_type(buffer))); // double parenthesis here for "most vexing parse" nonsense
vec.reserve(stack_size); // attempt to reserve space for 4 elements
std::cout << vec.capacity() << std::endl;
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
vec.push_back(40);
// Assert that the vector is actually using our stack
//
assert(
std::equal(
vec.begin(),
vec.end(),
buffer,
[](const int& v1, const int& v2) {
return &v1 == &v2;
}
)
);
// Output some values in the stack, we see it is the same values we
// inserted in our vector.
//
std::cout << buffer[0] << std::endl;
std::cout << buffer[1] << std::endl;
std::cout << buffer[2] << std::endl;
std::cout << buffer[3] << std::endl;
// Attempt to push back some more values. Since our stack allocator only has
// room for 4 elements, we cannot satisfy the request for an 8 element buffer.
// So, the allocator quietly falls back on using std::allocator.
//
// Alternatively, you could modify the stack_allocator implementation
// to throw std::bad_alloc
//
vec.push_back(50);
vec.push_back(60);
vec.push_back(70);
vec.push_back(80);
// Assert that we are no longer using the stack buffer
//
assert(
!std::equal(
vec.begin(),
vec.end(),
buffer,
[](const int& v1, const int& v2) {
return &v1 == &v2;
}
)
);
// Print out all the values in our vector just to make sure
// everything is sane.
//
for (auto v : vec) std::cout << v << ", ";
std::cout << std::endl;
std::aligned_storage<T, alignof(T)>
创建实际的堆栈缓冲区。
deallocate()
时,传入的指针是最后分配的块。如果传入的指针不是 LIFO 顺序的释放,Hinnant 的实现将什么也不做。这将使您能够使用
std::vector
无需提前保留,因为分配器基本上会忽略 vector 尝试释放初始缓冲区的尝试。但这也有点模糊了分配器的语义,并且依赖于非常明确地绑定(bind)到方式
std::vector
的行为。已知有效。我的感觉是,我们不妨简单地说,将任何指针传递给
deallocate()
这不是通过
返回的最后一次通话 至
allocate()
将导致未定义的行为并将其留在那里。
new
/
malloc
'd buffers 可以说是实现定义的行为(即使使用
std::less
),这可能使得无法编写符合标准的堆栈分配器实现,该实现依赖于堆分配。 (但实际上这无关紧要,除非您在 MS-DOS 上运行 80286。)
关于c++ - 基于堆栈缓冲区的 STL 分配器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8049657/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 4 年前。
以下 C++ 代码和 Makefile 产生了一个无法理解的编译错误(对我来说)。谁能解释一下 问题到底是什么? 修复此代码需要做什么?能举个例子吗? 我在 Cygwin 的 GCC 上成功编译了这段
我大量使用 BOOST_FOREACH 来迭代容器,并且由于我最近转向 c++0x,我认为我可以用基于范围的 替换 BOOST_FOREACH >for 构造。下面这段代码 #include #inc
我编写了代码,允许按照输入的顺序遍历映射数据。 我编写了几次代码的解决方案是: 给定键类型 K 和数据类型 D, 标准:: map std::向量 如果想随机查找数据条目,请使用 map.find(K
我在 cygwin 上使用 gcc 3.4.4。我在下面的代码中收到了这个相当令人费解的 STL 错误消息,它根本不使用 STL: #include using namespace std; con
我正在使用 STL 函数 count_if 来计算所有正值在 double vector 中。例如我的代码是这样的: vector Array(1,1.0) Array.push_back(-1.
我正在尝试使用 numpy-STL 从 STL 模型中提取顶点以用于相干点漂移注册。你如何提取顶点?我了解如何从顶点和面列表创建网格,但不了解如何倒退。 我试过:从顶点和面创建一个新网格。导入创建的网
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html 根据那篇文章,STL 不适合游戏开发。 你对此有何看法? 我目前的
在幕后,STL 映射是一棵红黑树,它使用其键的 typename _Rb_tree::iterator _Rb_tree:: find(const _Key& __k) { iterator _
我对 C++ 有很好的了解,但从未深入研究 STL。我必须学习 STL 的哪一部分才能提高工作效率并减少工作中的缺陷? 谢谢。 最佳答案 I have good knowledge of C++ 恕我
map rollCallRegister; map :: iterator rollCallRegisterIter; pair , bool> returnPair; rollCallRegi
在查看一些算法的模板名称时, 我看到这个名字对应于一个图书馆的概念。 取std::mismatch例如。 template std::pair mismatch( InputIt1 first1, I
我想对 class Person 的对象数组进行排序基于其数据成员' age '.我将对象存储在 vector v 中. 据我所知,至少有 4 种方法可以执行此操作,根据下面编写的方法,我有以下问题。
我对 gcc 或 Visual Studio 打包之外的 STL 实现感到好奇,因此快速 Google 搜索出现了一些结果,例如: Apache stdcxx uSTL rdeSTL 在什么情况下应该
我可以使用例如std::vector吗?在 macOs/XCode 的 DriverKit 驱动程序中? DriverKit 有一些容器类,如 OSArray https://developer.ap
我找不到任何关于如何将范围与容器结合使用的好文档。我正在尝试使用给定的 .insertAfter() 函数将一个元素插入到 SList 中。它需要一个范围,但我不知道如何检索它。 有人可以发布一两个示
如何在(例如)STL 容器中引入聚合初始化支持以正确构造它们?我的意思是: struct A { int i; char c; }; std::list l; // empty l.insert(st
我有一个 STL map : std::map > my_map; 我有两个变量: string name; int age; 这些变量的值发生变化,但本质上我想要做的是: 如果键名不存在,则创建键名
我是 C++ 的新手,请求帮助解决问题。 我正在编写一个简单的 STL 样式函数,它应该返回序列的中间元素( vector 、列表等) 这是我的函数,我尝试使用迭代器的概念 template It
如果我将几个水果名称推回第一个STL列表,同时,我将每个水果的编号推回第二个STL列表;如果我想按字母顺序对第一个STL列表进行排序,我该如何按水果STL列表的顺序对第二个STL列表进行排序? 最佳答
我是一名优秀的程序员,十分优秀!