- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我想知道是否有一个符合C++标准库要求的allocator
,它使用生活在堆栈中的(固定大小的)缓冲区,是否可行。
以某种方式,尽管在其他地方可能已经隐式回答了这个问题,但似乎还没有以这种方式问过这个问题。
基本上,就我的搜索而言,似乎应该可以创建使用固定大小缓冲区的分配器。现在,乍看之下,这应该意味着还应该有一个使用固定大小的缓冲区的“分配器”,该缓冲区在栈上“存在”,但确实确实没有广泛的实现。
让我举一个例子说明我的意思:
{ ...
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
没有默认的ctor -而且我在想
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 将其容量增加到小于该值时,都会发生undefined行为。
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 尝试取消分配初始缓冲区的尝试。但这也使分配器的语义有些模糊,并且依赖于行为,该行为与
std::vector
已知的工作方式特别相关。我的感觉是,我们也可以简单地说,将未通过
上次调用返回的未传递给
deallocate()
的任何指针传递给
allocate()
,将导致未定义的行为,并将其留在那。
new
/
malloc
'd缓冲区的两个指针的顺序可以说是实现定义的行为(即使使用
std::less
),这也许使得编写符合标准的堆栈分配器实现成为不可能,该实现依赖于堆分配。 (但是实际上,除非您在MS-DOS上运行80286,否则这并不重要。)
关于c++ - 基于堆栈缓冲区的STL分配器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23829088/
我有一个 map我需要插入和删除 Foo * 的地方.用法看起来像 map mapping; while( a long time) { // make ne
我想知道这是做什么的: std::basic_string, std::allocator>:: basic_string, std::allocator> (&myText, "hello worl
是否可以在 C++ 中创建一个像这样简单工作的自定义分配器: { // Limit memory to 1024 KB ScopedMemoryPool memoryPool(1024
我正在使用提到的 STL 分配器 here . 我所做的唯一更改是我从一个名为 Object 的基类继承,并且我使用基类的 new 和 delete 函数进行分配。 class MyAlloc
我有一段代码可以创建数千个对象,并将它们附加到一个 vector 中。下面的代码只是一个正在做的事情的例子,尽管构造函数有一些参数,而for实际上并没有那个条件,但它起到了表明它运行了数千次的目的。
这里有两个问题。首先,如果我需要在 Clone 之前创建 b2BlockAllocator 然后在克隆之后删除(在哪里?)? Xcode 分析工具未显示 C++ 泄漏... b2FixtureDef
我想创建一个不可复制的分配器(在 C++14 中),它只分配一个 std::vector 可以使用的固定内存块。我想防止分配器(以及 vector )被复制,以防止用户意外分配内存。分配器仅用于 st
我在 http://msdn.microsoft.com/en-us/library/ee292117.aspx 上看到和 http://msdn.microsoft.com/en-us/librar
我想用更健壮的分配器替换标准分配器(C++ 标准只需要对 vector::resize 进行溢出检查)。许多库提供的各种 C++ 分配器在进行负面 self 测试时会一败涂地。 我可以使用更强大的分配
我的 STL 容器中的内存使用预计是不稳定的——也就是说它会经常收缩和增长。我正在考虑通过为 STL 容器类型声明指定一个分配器来解决这个问题。我知道矿池分配器旨在处理这种情况,但我担心的是波动性将超
我有一个大量使用 STL 容器和字符串的大型(>250 个文件)库的源代码。我需要在有限堆的嵌入式环境中运行它,所以我想确保这个库本身的堆使用受到限制。 显而易见的解决方案是创建一个分配器,但修改整个
我想知道有一个符合 C++ 标准的库是否可行 allocator使用位于堆栈中的(固定大小的)缓冲区。 不知何故,这个问题似乎还没有在 SO 上这样问过,尽管它可能已经在其他地方得到了隐含的回答。 所
我观察到我的 MSVC10 副本附带的容器似乎允许基于状态的分配器,并编写了一个简单的池分配器,为特定类型分配池。 然而,我发现如果_ITERATOR_DEBUG_LEVEL != 0 MSVC 向量
据我所知,当 vector 空间不足时,分配器用于创建新空间。但是,我想创建一个自定义调整大小策略,该策略将移除底部 25% 的元素并始终保持相同的大小。这是为了构建一个空间有限的缓存。 有没有我可以
我目前正在尝试使用 Microsoft Visual Studio 2012 编译一个相当大的项目。我发现它在旧版本上编译得很好,但是对于这个版本,我在 std::list 的任何地方都会出错仅与一个
因此,在所提供代码的下一行,我有 IntelliSense 警告:“没有可用的成员”。怎么了?在正常情况下,似乎有选项,如“分配”、“解除分配”等。 namespace MyLib { tem
我正在尝试在 Microsoft visual studio 2013 on C++ 上编译为 linux 编写的程序。 声明 sdesc_t *ret = _malloc(sizeof(sdesc_
由于我工作的政策,我无法使用高于 1.33.1 的 Boost 版本,也无法使用高于 4.1.2 的 GCC 版本。是的,这是垃圾,但我对此无能为力。 Boost 1.33.1 不包含进程间库。 也就
我正在为 T 类型的数组实现资源分配克隆操作。直接的实现使用 new T[sz],然后是从源到新数组的 std::copy 调用。它遍历内存两次。 我想分配原始内存然后使用 std::uninitia
我们有一个库,它通过 extern "C" 提供 C 接口(interface),并从 C 代码中使用,但为了方便起见,它内部使用了 STL 容器和一些 C++ 功能,如 RAII。 现在有一个新的要
我是一名优秀的程序员,十分优秀!