- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
C++ 分配器(如 std::vector
使用的那样)很难操作。我知道他们改变了很多以允许有状态的分配器和 PMR,从而导致一些问题。我的核心问题是:如果分配器旨在替换 new
和 delete
,为什么它们只提供像 malloc
和 free 这样的 API
?我理解为什么,例如,std::vector
需要一个 malloc
接口(interface),因为它需要在不调用构造函数的情况下分配一个缓冲区,但总的来说,我们似乎缺少这些功能:
#include <cassert>
#include <iostream>
#include <memory>
//! Rebind alloc to type T
template <typename T, typename Alloc>
auto rebound_allocator(const Alloc& alloc) {
return typename std::allocator_traits<Alloc>::template rebind_alloc<T>{alloc};
}
//! Like operator delete but for a single T allocated by rebound_allocator<T>(alloc).
template <typename T, typename Alloc>
void allocator_delete(const Alloc& alloc, T* ptr) {
assert(ptr);
auto a = rebound_allocator<T>(alloc);
using traits_t = std::allocator_traits<decltype(a)>;
// Should we try/catch around destroy and always deallocate?
traits_t::destroy(a, ptr);
traits_t::deallocate(a, ptr, 1);
}
//! Returned memory must be freed with, e.g., allocator_delete(alloc, ptr).
template <typename T, typename Alloc, typename... Args>
[[nodiscard]] T* allocator_new(const Alloc& alloc, Args&&... args) {
auto a = rebound_allocator<T>(alloc);
using traits_t = std::allocator_traits<decltype(a)>;
auto deallocate = [&a](T* ptr) { traits_t::deallocate(a, ptr, 1); };
// Hold in a unique_ptr to deallocate if construction throws.
auto buf = std::unique_ptr<T, decltype(deallocate)>(traits_t::allocate(a, 1), deallocate);
traits_t::construct(a, buf.get(), std::forward<Args>(args)...);
return buf.release();
}
//! Like make_unique. Beware: The allocator is is referenced by the deleter!
template <typename T, typename Alloc, typename... Args>
[[nodiscard]] auto allocator_make_unique(const Alloc& alloc, Args&&... args) {
auto dtor = [&alloc](T* ptr) { allocator_delete<T>(alloc, ptr); };
return std::unique_ptr<T, decltype(dtor)>(allocator_new<T>(alloc, std::forward<Args>(args)...),
dtor);
}
struct S {
float x;
S(float x) : x(x) { std::cout << "S::S()" << std::endl; }
~S() { std::cout << "S::~S()" << std::endl; }
};
int main() {
std::allocator<int> alloc;
auto ptr = allocator_make_unique<S>(alloc, 42.5f);
assert(ptr);
std::cout << ptr->x << std::endl;
}
输出:
S::S()
42.5
S::~S()
https://godbolt.org/z/sheec6br3
我错过了什么吗?这是使用分配器实现 new
和 delete
以及 make_unique
的正确方法吗?如果是这样,这真的不是标准库提供的吗?
编辑:我认为(但不确定?)如果 T
是分配器感知的,traits_t::construct(a, ptr, n)
会将自身传播到创建的对象中?
编辑:这是清理后的版本:https://godbolt.org/z/47Tdzf4W7
最佳答案
My core question is: if allocators are intended to replace new and delete, why do they only provide an API like malloc and free?
分配器的API之所以如此,是因为分配器的一个重要点是内存分配和对象创建必须分开。例如,这是实现 std::vector
等容器所必需的。分配器是 operator new/delete 的泛化,而不是 new 表达式的泛化。
is this really not provided by the standard library?
不,标准库不提供这些函数。
Is this the right way to implement essentially new and delete and make_unique using allocators?
auto dtor = [&alloc](T* ptr) { destruct_and_deallocate(alloc, ptr); };
^
通过引用将分配器捕获到删除器中似乎很糟糕。为了安全起见,应该复制它。
其他建议:
在 std::allocator
的默认情况下,我们希望避免支付删除器的开销。考虑在使用 std::allocator
时添加委托(delegate)给 std::make_unique
的特化。
您可以通过将中间唯一指针与仅释放的删除器一起使用来避免 try-catch:
T* ptr = traits_t::allocate(rebound_alloc, 1);
auto dealloc = [&](T* ptr) { traits_t::deallocate(rebound_alloc, ptr, 1); };
std::unique_ptr<T, decltype(dealloc)> storage(ptr, dealloc);
traits_t::construct(rebound_alloc, storage.get(), std::forward<Args>(args)...);
auto dtor = [alloc](T* ptr) { destruct_and_deallocate(alloc, ptr); };
return std::unique_ptr<T, decltype(dtor)>(storage.release(), dtor);
Edit: I think (but am not sure?) that if T is allocator-aware, traits_t::construct(a, ptr, n) will propagate itself into the created object?
不,对象不知道创建它们或分配内存的分配器。 “分配器感知”容器只是通用模板,允许用户提供自定义分配器,并避免通过其他方式分配内存。
关于c++ - 使用分配器的 new 和 delete 等同于什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70019488/
判断这2个相似的Uris实际上相同的标准方法是什么? var a = new Uri("http://sample.com/sample/"); var b = new Uri("http://sam
这个问题在这里已经有了答案: Why does "true" == true show false in JavaScript? (5 个答案) 关闭 5 年前。 可能我很困惑,但我无法理解这个愚蠢
我是一名优秀的程序员,十分优秀!