作为这个问题的一个例子,我将使用std::vector.
其文件定义如下:
template<class T, class Allocator = std::allocator<T>>
class vector;
Run Code Online (Sandbox Code Playgroud)
正如所料,如果T是它的类型,分配器应该偏向于T.
无论如何,下面的代码编译没有错误(至少,使用GCC)并运行:
#include<vector>
#include<memory>
#include<string>
struct S {
int i;
double d;
std::string s;
};
int main() {
std::allocator<int> alloc;
std::vector<S, std::allocator<int>> v{alloc};
v.push_back(S{});
}
Run Code Online (Sandbox Code Playgroud)
在这里,我创建一个向量的小号通过专注于一个allocator INT.
这是合法代码吗?我应该期待未定义的行为吗?还有什么?
我不完全明白这背后的魔力以及为什么STL让用户这样做.
另一方面,rebind仅在文档中提及类似的事情std::list,我不知道它们是否也适用于这种情况.
在其他方面,如果它有效,我想知道它为什么有效(它rebind背后是什么?),否则我想知道为什么它被允许.
我可能误解了有关分配器的一些概念.但我真的不知道为什么我们需要std::size_t传递一个参数allocate来指示要分配的对象数.参数是用于分配内存区域,如数组还是向量?
如果是,那么我的自定义分配器如何知道先前返回的指针是指向某个区域还是仅指向某个对象?我的分配器是否有责任记录这些指针?
如果他们不是,那么为什么我们需要这个论点呢?
根据当前标准 (20.7.9),std::allocator有一个成员propagate_on_container_move_assignment设置为true_type:
模板类分配器
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* 指针;
typedef const T* const_pointer;
typedef T&参考;
typedef const T& const_reference;
typedef T value_type;
模板结构重新绑定 { typedef 分配器其他;};
typedef true_typepropagate_on_container_move_assignment;
typedef true_type is_always_equal;
[...]
std::allocator没有数据成员,并且总是与任何其他std::allocator. 是否有任何理由在移动分配时移动这些默认分配器?
在 SFINAE 上下文中编写allocator_traits<T>::value_type似乎是测试类型是否T实际上是分配器的可行方法。然而,这并不是特别优雅,而且我过去也曾被极端情况所困扰。
因此我的问题是:在 T 是分配器的情况下,如何最好地实现is_allocator<T>包含 a of true 的特征,否则如何实现包含 ::false 的特征?::value
在c ++ 17之前,如果您有类似的分配器,则Allocator<typename, size_t>可以使用rebind结构。但是现在,在C ++ 17中,不推荐使用rebind结构。从中构造an的解决方案allocator<T,size_t>是allocator<T2, size_t>什么?
笔记:
我知道通常的原因是可能的:没有人想到它/写过论文/WG21 认为这不值得付出努力,我对阻止潜在实施的技术问题更感兴趣,而不是对这个功能的效用价值感兴趣。
我一直觉得很奇怪,这并不工作(甚至概念之前,因为我们可以使用enable_if)
#include <vector>
#include <boost/align/aligned_allocator.hpp>
int main()
{
std::vector<int> a{1,2,3};
std::vector<int, boost::alignment::aligned_allocator<int,64>> b{1,2,3};
return a==b;
}
Run Code Online (Sandbox Code Playgroud)
原因是分配器不会影响存储在容器中的值(我知道值可能会在运算符 == 中使用它们的地址,我说的是“正常”类型)。
所以我的问题是:如果我们想用 C++20 概念来做这件事,我们可以在不破坏任何现有代码的情况下引入这个功能吗?
我正在研究C++17中的多态内存分配。我修改了一个使用 monotonic_buffer_resource 进行向量分配的示例,以使用synchronous_pool_resource。我发现了一种奇怪的行为。具体来说,有很多内存分配,只是为了向量中的两次加法。我没有运行基准测试,但我认为这对性能造成了巨大的损失
该程序是使用 O2 g++ -std=c++17 -O2 -Wall -pedantic编译的
下面是代码
class debug_resource : public std::pmr::memory_resource {
public:
explicit debug_resource(std::string name,
std::pmr::memory_resource* up = std::pmr::get_default_resource())
: _name{ std::move(name) }, _upstream{ up }
{ }
void* do_allocate(size_t bytes, size_t alignment) override {
std::cout << _name << " do_allocate(): " << bytes << '\n';
void* ret = _upstream->allocate(bytes, alignment);
return ret;
}
void do_deallocate(void* ptr, size_t bytes, size_t alignment) override {
std::cout << _name << " do_deallocate(): " << bytes << '\n'; …Run Code Online (Sandbox Code Playgroud) 是否std::vec::shrink_to_fit分配一个新的、较小的vec.len()数据缓冲区,复制到其中,并销毁旧缓冲区,或者是否以某种方式向内存分配器指示可以取消分配缓冲区的未初始化部分,并简单地释放该部分内存?这可能吗?这取决于内存分配器吗?
我很抱歉在这里问一个切题的问题,但如果可能的话,为什么我们不实现从向量前面弹出作为一个简单的“std::mem::size_of<T>()从缓冲区开始释放内存量,并递增我们的指针移动一位”,而不是将所有元素移动一位?
我想将TCMalloc与STL容器一起使用,所以我需要一个用TCMalloc构建的分配器(就像带有TBB malloc的tbb_allocator).我找不到任何TCMalloc文档(如果它被称为文档).所以我开始探索头文件并找到一个名为的类STL_Allocator.但有些事情对我来说并不清楚.来自stl_allocator.h的报价:
// Generic allocator class for STL objects
// that uses a given type-less allocator Alloc, which must provide:
// static void* Alloc::Allocate(size_t size);
// static void Alloc::Free(void* ptr, size_t size);
//
// STL_Allocator<T, MyAlloc> provides the same thread-safety
// guarantees as MyAlloc.
//
// Usage example:
// set<T, less<T>, STL_Allocator<T, MyAlloc> > my_set;
// CAVEAT: Parts of the code below are probably specific
// to the STL version(s) we are using.
// The code …Run Code Online (Sandbox Code Playgroud) 在下面的代码中是函数make_vector().它创建一个向量并将其返回给调用者.我希望能够为要使用的向量指定分配器,但默认情况下使用默认的std :: allocator.这是因为在某些情况下,默认分配器是我所需要的,但有时我需要从一些预定义的内存池中分配.
我最接近的是make_vector2()函数模板.它适用于std :: allocator,但我不知道如何将'arena'参数传递给我的自定义分配器.
Hopefull这个有用的c ++ 11示例将更好地解释它:
#include <malloc.h>
#include <cinttypes>
#include <cstddef>
#include <iostream>
#include <limits>
#include <stdexcept>
#include <vector>
namespace mem
{
// Memory arena to allocate from.
enum class ARENA
{
TEXTURES,
FONTS,
SCRIPTS
};
// Allocate block from specific arena.
void *malloc( const std::size_t size, const ARENA arena )
{
return std::malloc( size /*, arena */ );
}
// Free block from specific arena.
void free( void *ptr, const ARENA arena )
{
std::free( …Run Code Online (Sandbox Code Playgroud) allocator ×10
c++ ×9
c++11 ×2
stl ×2
c++-concepts ×1
c++14 ×1
c++17 ×1
c++20 ×1
c++pmr ×1
containers ×1
heap-memory ×1
rust ×1
tcmalloc ×1
templates ×1
type-traits ×1
vector ×1