据我所知,std::allocator是由库引入的,用于分配未初始化的未构造内存块。所以:
std::allocator<int> a;
auto ptr = a.allocate(100);
auto e = ptr;
while (e != ptr + 5)
a.construct(e++, 0);
for (auto tmp = ptr; tmp != e; )
std::cout << *tmp++ << ", ";
std::cout << std::endl;
std::allocator<int> a2;
std::allocator<int> a3 = a;
for (auto tmp = ptr; tmp != e; )
a.destroy(tmp++);
//for (auto tmp = ptr; tmp != e; )
// a2.destroy(tmp++); // is it UB using a2 here to destroy elements?
//for (auto tmp = …Run Code Online (Sandbox Code Playgroud) 我最近写了一篇小文章malloc,想知道它是否是一个凹凸分配器。我想知道这一点,因为(如果我错了,请纠正我)我相信实际的malloc(使用而mmap不是sbrk)使用相同的技术(某种程度上),但凹凸分配器只会增加堆位置。这是我的代码:
#include <cstdio>
#include <cstddef>
#include <unistd.h>
#define word_size sizeof(intptr_t)
#define align(n) ((n + word_size - 1) & ~(word_size - 1))
void* my_malloc(size_t size) {
void* p = sbrk(0);
if (sbrk(align(size)) == (void*) -1)
return NULL; // failed
return p;
}
int main() {
int* foo = (int*) my_malloc(1);
*foo = 100;
printf("%d\n", *foo);
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用 a 创建共享指针std::pmr::monotonic_buffer_resource,但无法编译它。我缺少什么?
https://godbolt.org/z/R9jdju
#include <memory>
#include <memory_resource>
int main() {
char buffer[100];
std::pmr::monotonic_buffer_resource mbr(buffer, 100);
std::shared_ptr<double> sp = std::allocate_shared<double>(mbr);
}
Run Code Online (Sandbox Code Playgroud)
在 /opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/ext/alloc_traits.h:34 包含的文件中,
来自/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/stl_uninitialized.h:67,
来自/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/memory:66,
来自<来源>:1:
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/alloc_traits.h:使用 __alloc_rebind = typename std::__allocator_traits_base::__rebind 替换 'template<class _Alloc, class _Up> <_Alloc, _Up>::type [with _Alloc = std::pmr::monotonic_buffer_resource; _Up = std::_Sp_counted_ptr_inplace<double, std::pmr::monotonic_buffer_resource, __gnu_cxx::_S_atomic>]':
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/shared_ptr_base.h:542:13:需要从 'class std::_Sp_counted_ptr_inplace<double, std::pmr::monotonic_buffer_resource, __gnu_cxx::_S_atomic>'
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/shared_ptr_base.h:679:43:需要来自 'std::__shared_count<_Lp>::__shared_count(_Tp*&, std ::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = double; _Alloc = std::pmr::monotonic_buffer_resource; _Args = {}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]'
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/bits/shared_ptr_base.h:1371:71:需要来自 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std:: _Sp_alloc_shared_tag<_Tp>, _Args&& … 抛出:
allocate可能抛出适当的异常。
其他地方暗示的“适当”有什么限制吗?
有效的自定义分配器可以double在任何请求上抛出 a 吗?
上下文:使用分配器的函数的实现noexcept,但具有后备策略,以便在所有分配失败时执行某些操作。
我真的没有得到模板std :: vector的字段,第一个指定类型,例如一个类,但我没有得到分配器,指针和引用变量.
我将提供一个简单的例子,我想使用类人的向量,所以我不得不对模板向量说:嘿,存储我一些人的,但我还必须告诉向量如何分配该类.(1)该示例的语法如何?
一些代码开头:
旁注,在人的构造函数中,c(2)我应该使用日期*?
class date
{
public:
int m_nMonth;
int m_nDay;
int m_nYear;
int getMonth(return m_nMonth;)
int getDay(return m_nDay;)
int getYear(return m_nYear;)
void setDate(int month, int day, int year)
{
m_nMonth=month;
m_nDay=day;
m_nYear=year;
}
date()
{
setDate(0,0,0);
}
date(int month, int day, int year)
{
setDate(month,day,year);
}
void printDate()
{
printf("%d/%d/%d", m_nMonth, m_nDay, m_nYear);
}
}
class person
{
public:
int m_nID;
char m_sName[128];
char m_sSurname[128];
date m_cBirthDay;
void setName(const char* name)
{ …Run Code Online (Sandbox Code Playgroud) 我让我的对象使用重载的new/delete操作符,因为我使用内存池来分配它们的内存.他们看起来像这样:
class Foo{
public:
void* operator new(size_t nbytes){
return MemoryManager::GetInstance().AllocFooTypeMemory();
}
void operator delete(void* p)
{
MemoryManager::GetInstance().FreeFooTypeMemory(p);
}
};
Run Code Online (Sandbox Code Playgroud)
现在,我的问题是当我创建一个Foo指针的STL容器时它是如何工作的?这里写的是默认的STL分配器使用:: operator new来在容器中分配内存.什么时候使用它?我试着看看在调用时是否会触发Foo的新内容
std::vector<Foo*> fooVector;
fooVector.reserve(10);
Run Code Online (Sandbox Code Playgroud)
但没有任何反应.
我有几个问题:
我是否正确地暗示在这种情况下,分配器仅为指针分配内存?
是否意味着当容器包含对象而不是指针时,分配器在Foo上调用"new"?
如果是,那么这是否意味着如果我已经使用池在对象中分配内存(如在Foo示例中),那么我不需要使用mem pool编写自定义分配器?
更新:
为了说清楚,我考虑到只有使用内存池重载new/delete的对象与这个问题有关.我完全知道没有new/deleted重载的对象仍然使用默认堆作为源动态内存分配.
我不是自定义分配器的用户,但我想知道是否可以使用自定义分配器来重新定义增长策略.例如,在大多数实现中,a std::vector几何增长.是否有可能为算术增长改变此策略,例如每次需要重新分配时添加10个元素.如果答案是肯定的,那该怎么办呢?
我正在尝试编写自己的Allocator,可以在STL中使用.到目前为止我几乎可以成功完成,但有一个功能我有我的问题:
的Allocator在STL使用应当提供函数construct[使用来自标准分配器示例new&delete]:
// initialize elements of allocated storage p with value value
void construct (T* p, const T& value)
{
::new((void*)p)T(value);
}
Run Code Online (Sandbox Code Playgroud)
我被困在如何使用我自己的函数重写new它,它取代了初始化它的关键字value.
此函数construct例如在此代码中使用:fileLines.push_back( fileLine );
哪里
MyVector<MyString> fileLines;
MyString fileLine;
Run Code Online (Sandbox Code Playgroud)
这些是我typedefs使用自己的地方Allocator:
template <typename T> using MyVector = std::vector<T, Allocator<T>>;
using MyString = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
Run Code Online (Sandbox Code Playgroud)
我很困惑,因为在这里被分配pointer到T可以是例如[我理解正确的话] MySstring.
难道我的理解是正确的指针-根据所分配new-将有10个字节,如果value是123456789 …
据我了解,自定义分配器必须符合分配器概念的要求。但是,基于该界面,我看不出当向量耗尽储备时我将如何选择新的分配量。
例如,我机器上的当前实现每次reserve在push_back(). 我想提供一个速度慢且内存敏感的自定义分配器。它只会分配前一个capacity+1来容纳新元素。
这些是我正在研究的概念的接口:
a.allocate(n)
a.allocate(n, cvptr) (optional)
Run Code Online (Sandbox Code Playgroud)
我制作了一个工作样板分配器,如下所示:
#include <limits>
#include <iostream>
template <class T> class MyAlloc {
public:
// type definitions
typedef T value_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
pointer address(reference value) const {
return &value;
}
const_pointer address(const_reference value) const {
return &value;
}
size_type max_size() const throw() {
return std::numeric_limits<std::size_t>::max() / sizeof(T);
} …Run Code Online (Sandbox Code Playgroud) 我最近有兴趣std::allocator,认为它可能解决我对C++代码的一些设计决定的问题.
现在我已经阅读了一些关于它的文档,观看了一些视频,比如Andrei Alexandrescu在2015年CppCon上的一个视频,我现在基本上明白我不应该使用它们,因为它们不是按照我认为分配器可能工作的方式工作的.
话虽如此,在实现这一点之前,我编写了一些测试代码,以了解自定义子类如何std::allocator工作.
显然,没有按预期工作...... :)
所以问题不在于如何在C++中使用分配器,而是我很想知道为什么我的测试代码(下面提供)不起作用.
不是因为我想使用自定义分配器.只是好奇看到确切的原因......
typedef std::basic_string< char, std::char_traits< char >, TestAllocator< char > > TestString;
int main( void )
{
TestString s1( "hello" );
TestString s2( s1 );
s1 += ", world";
std::vector< int, TestAllocator< int > > v;
v.push_back( 42 );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
完整的代码TestAllocator在本问题的最后提供.
在这里,我只是用我的自定义分配器一些std::basic_string,并用std::vector.
有了std::basic_string,我可以看到我的分配器的实例实际上是创建的,但是没有调用任何方法......
所以看起来它根本就没用过.
但是std::vector,我自己的allocate方法实际上被调用了.
那么为什么这里有区别?
我尝试过不同的编译器和C++版本.看起来像旧的GCC版本,使用C++ 98,会调用allocate我的TestString类型,但不会调用C++ 11及更高版本的新版本.铿也不打电话 …
allocator ×10
c++ ×8
vector ×3
c++11 ×2
std ×2
stl ×2
allocation ×1
c ×1
c++-concepts ×1
c++pmr ×1
class ×1
malloc ×1
new-operator ×1
shared-ptr ×1