该标准C++17
包括一个新的命名空间,pmr
包括一组以名称分组的类memory_resource
.
在网上搜索后,我发现很少有关于它的庸俗信息,直接后果是这个问题:
背后的主要思想pmr
是pmr::memory_resource
什么?
详细说明问题,我头脑中的一些问号是:
allocator
?allocator
提供给容器构造函数的运行时?(例如用于测试目的)语境:
在创建memory pool
分配器的过程中,我找到了有关此命名空间的信息.读名字pool_options
或者polymorphic_allocator
引起我的注意.
相关问题:
我试图了解如何正确编写AllocatorAware容器.
我的理解是propagate_on_container_move_assignment
typedef表示Allocator
当Container本身被移动分配时是否需要复制某种类型.
所以,既然我找不到任何这方面的例子,我自己的抨击就像下面这样:
给定容器类型Container
,Allocator
类型allocator_type
和内部allocator_type
数据成员m_alloc
:
Container& operator = (Container&& other)
{
if (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value)
{
m_alloc = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
other.m_alloc
);
}
return *this;
}
Run Code Online (Sandbox Code Playgroud)
它是否正确?
此外,另一个混乱的来源是嵌套的typedef propagate_on_container_move/copy_assignment
专门讨论赋值 ...但是构造函数呢?移动构造函数或AllocatorAware
容器的复制构造函数是否还需要检查这些typedef?我认为这里的答案是肯定的 ......意思是,我还需要写:
Container(Container&& other)
{
if (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value)
{
m_alloc = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
other.m_alloc
);
}
}
Run Code Online (Sandbox Code Playgroud) std::allocator
是对底层内存模型的抽象,它包含了调用new
和的功能delete
. delete
虽然不需要大小,但是deallocate() 需要它.
void deallocate(T*p,std :: size_t n);
"参数n必须等于最初生成p的allocate()调用的第一个参数;否则,行为是未定义的."
为什么?
现在我要么在解除分配之前进行额外的计算,要么开始存储我传递给分配的大小.如果我没有使用分配器,我就不必这样做了.
我将构建一个自定义分配器,预分配一个大块(数组)来存储N
某些类的元素T
,然后只需增加数组内的索引来为服务分配请求.
因为我不希望对预分配块中的元素进行任何初始化,所以这样的东西不起作用:
T buffer[N];
Run Code Online (Sandbox Code Playgroud)
因为在这种情况下,T
将为N
块的元素调用构造函数.
既然我的理解是std::aligned_storage
不调用T
构造函数,我想使用std::aligned_storage
,像这样:
std::aligned_storage<
N * sizeof(T),
std::alignment_of<T>::value
>::type buffer;
T* base = static_cast<T*>( static_cast<void*>(&buffer) );
Run Code Online (Sandbox Code Playgroud)
然后,当请求T的分配(直到(base+N)
)时,分配器可以仅增加基指针,并且在需要时可以在适当的位置构建T (具有放置new
).
我想使用此方案为STL容器定义自定义分配器.但是,在我看来,重新绑定可能存在问题.事实上,如果我的理解是正确的,一个STL分配器应支持从类型重新绑定T
到一个类型U
,例如,因为喜欢的容器std::list<T>
(或其它基于节点的容器一样std::map
)使用allocator分配的节点上,但不是类型T
,但不同type U
(包含T
节点的"header"开头信息).那么,上述std::aligned_storage
方法是否适用于重新绑定?或者(我认为)T
s 的正确对齐并不意味着另一种不同类型的正确对齐U
?
怎么可以解决这个问题?
我怎样才能定义上述内容buffer …
为了保存一些代码,我可以说我有一个名为的自定义分配器MyAlloc
,我已成功使用std::vector<int>
如下:
std::vector<int,MyAlloc<int>> vec;
Run Code Online (Sandbox Code Playgroud)
现在我想使用自定义分配器在std :: function中保存lambda,我该怎么做?
我失败的尝试:
int i[100];
std::function<void(int)> f(MyAlloc<void/*what to put here?*/>{},[i](int in){
//...
});
Run Code Online (Sandbox Code Playgroud)
更新: std :: function中的分配器已被删除
从我在http://en.cppreference.com/w/cpp/memory/allocator中读到的内容来看,分配器的大部分功能现在都将被弃用.问题是,如何在新代码中使用分配器?现在"正确"的方式是什么?
从我在文档中推断出来的,construct
是分配器特性的一部分,而不是分配器本身.
我正在构建一个自定义容器,这里是一个非常简单的构造函数版本,这是一个很好的新设计用法吗?
container::container(std::size_t size, T const& value, Allocator const& allocator) : allocator_(allocator){
data_ = std::allocator_traits<Alloc>::allocate(allocator_, size);
for(auto ptr = data_; ptr != data_ + size; ++ptr){
std::allocator_traits<Allocator>::construct(allocator_, ptr, value)
}
}
Run Code Online (Sandbox Code Playgroud)
我试图std::for_each
在循环中使用一个算法(如),但我没有设法使用一个没有地址(operator&
).
我在哪里可以找到现代分配器的完整示例?
经过一些调整,我找到了一种方法来使用算法而不是原始循环(可以传递执行策略).我不是很确定,但可能是这样的:
data_ = std::allocator_traits<Allocator>::allocate(allocator_, size);
std::for_each([policy? deduced from allocator?,]
boost::make_counting_iterator(data_),
boost::make_counting_iterator(data_ + size),
[&](auto ptr){std::allocator_traits<Allocator>::construct(allocator_, ptr, value);}
);
Run Code Online (Sandbox Code Playgroud) 根据cppref:
std::allocator<T>::allocate_at_least
通过调用 (可能提供附加参数)分配
count * sizeof(T)
未初始化存储的字节,其中count
是不小于 的未指定整数值,但未指定何时以及如何调用此函数。n
::operator new
std::align_val_t
T[count]
然后,该函数在存储中创建一个类型数组并开始其生命周期,但不会启动其任何元素的生命周期。
然而,我认为现有的std::allocator<T>::allocate
可以做同样的事情。
为什么我们需要 std::allocator<T>::allocate_at_least
C++23?
据我所知std::allocator<T>::construct
,在旧版本的C ++上仅需要两个参数;第一个是指向未构建的原始内存的指针,我们要在其中构造一个类型的对象,T
第二个是用于初始化该对象的元素类型的值。因此,调用了复制构造函数:
struct Foo {
Foo(int, int) { cout << "Foo(int, int)" << endl; }
/*explicit*/ Foo(int) { cout << "Foo(int)" << endl; }
Foo(const Foo&) { cout << "Foo(const Foo&)" << endl; }
};
int main(int argc, char* argv[]) {
allocator<Foo> a;
Foo* const p = a.allocate(200, NULL); // second parameter is required on C++98 but on C++11 it is optional
// Foo* const p = a.allocate(200); // works fine on C++11 but not on …
Run Code Online (Sandbox Code Playgroud) STL容器有一个模板参数来选择自定义分配器.花了一段时间,但我想我明白它是如何工作的.不知何故,它不是很好,因为给定的分配器类型不是直接使用,而是反弹到另一种类型的分配器.最后我可以使用它.
在阅读API之后,我意识到还有可能将allocator作为构造函数参数.但是,我如何知道容器使用哪种分配器,如果它在内部从模板参数重新绑定给定的分配器?
另外我读到C++ 11现在使用范围分配器,它允许重用容器的分配器来容纳容器.如何启用作用域分配器容器的实现与不知道作用域容器的容器大致不同?
不幸的是,我无法找到任何可以解释这一点的东西.谢谢你的回答!
这个问题是关于拥有指针,使用指针,智能指针,向量和分配器的。
我对代码体系结构的想法有些迷茫。此外,如果这个问题在某个地方已经有答案,1.抱歉,但是到目前为止我还没有找到满意的答案,并且2.请指出。
我的问题如下:
我有一个存储在向量中的“事物”,以及这些“事物”的几个“消费者”。因此,我的第一次尝试如下所示:
std::vector<thing> i_am_the_owner_of_things;
thing* get_thing_for_consumer() {
// some thing-selection logic
return &i_am_the_owner_of_things[5]; // 5 is just an example
}
...
// somewhere else in the code:
class consumer {
consumer() {
m_thing = get_thing_for_consumer();
}
thing* m_thing;
};
Run Code Online (Sandbox Code Playgroud)
在我的应用程序中,这是安全的,因为在任何情况下,“事物”的寿命都超过了“消费者”。但是,可以在运行时添加更多的“事物”,这可能会成为问题,因为如果std::vector<thing> i_am_the_owner_of_things;
重新分配了这些事物,则所有thing* m_thing
指针都将变为无效。
一种解决方案是将唯一的指针存储到“事物”,而不是直接存储“事物”,即如下所示:
std::vector<std::unique_ptr<thing>> i_am_the_owner_of_things;
thing* get_thing_for_consumer() {
// some thing-selection logic
return i_am_the_owner_of_things[5].get(); // 5 is just an example
}
...
// somewhere else in the code:
class consumer {
consumer() {
m_thing …
Run Code Online (Sandbox Code Playgroud) allocator ×10
c++ ×10
c++11 ×6
stl ×3
c++17 ×2
c++23 ×1
containers ×1
performance ×1
shared-ptr ×1
standards ×1
type-traits ×1
unique-ptr ×1