内存分配
头文件
内存分配的头文件都在 <stdlib.h>
malloc
函数定义:void* malloc( size_t size );
函数说明:从堆中(heap)分配未初始化的内存空间,其大小为 size。
返回值:分配成功则返回首地址,失败则返回 NULL。
是否线程安全: 是
size = 0: 报 implementation-defined 错误
calloc
函数定义:void* calloc( size_t num, size_t size );
函数说明:从堆中(heap)分配 num 个大小为 size 内存空间, 并初始化为0。
返回值:分配成功则返回首地址,失败则返回 NULL。
是否线程安全: 是
size = 0: 报 implementation-defined 错误
realloc
函数定义:void *realloc( void *ptr, size_t new_size );
函数说明:为 ptr 重新分配内存, 并把之前的内存内容拷贝过去(多出的内存未初始化)同时释放旧内存. 如果旧内存比 new_size 大, 则不会申请新内存, 同时旧内存内容保存不变.
返回值:分配成功则返回首地址,失败则返回 NULL。
是否线程安全: 是
new_size = 0: 报 implementation-defined 错误
free
函数定义:void free( void* ptr );
函数说明:释放之前申请的内存
返回值:空
是否线程安全: 是
ptr = NULL: 不做任何事情
aligned_alloc
函数定义:void *aligned_alloc( size_t alignment, size_t size );
函数说明:分配对齐的未初始化内存, size 参数是 alignment 的整数倍.
返回值:分配成功则返回首地址,失败则返回 NULL。
是否线程安全: 是
new_size = 0: 报 implementation-defined 错误
模版分配 std::allocator
底层
#if __cpp_aligned_new
if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
std::align_val_t __al = std::align_val_t(alignof(_Tp));
return static_cast<_Tp *>(::operator new(__n * sizeof(_Tp), __al));
}
#endif
return static_cast<_Tp *>(::operator new(__n * sizeof(_Tp)));
}
使用
#include <memory>
#include <iostream>
#include <string>
int main()
{
{
// default allocator for ints
std::allocator<int> alloc;
// demonstrating the few directly usable members
static_assert(std::is_same_v<int, decltype(alloc)::value_type>);
int* p = alloc.allocate(1); // space for one int
alloc.deallocate(p, 1); // and it is gone
// Even those can be used through traits though, so no need
using traits_t = std::allocator_traits<decltype(alloc)>; // The matching trait
p = traits_t::allocate(alloc, 1);
traits_t::construct(alloc, p, 7); // construct the int
std::cout << *p << '\n';
traits_t::deallocate(alloc, p, 1); // deallocate space for one int
}
{
// default allocator for strings
std::allocator<std::string> alloc;
// matching traits
using traits_t = std::allocator_traits<decltype(alloc)>;
// Rebinding the allocator using the trait for strings gets the same type
traits_t::rebind_alloc<std::string> alloc_ = alloc;
std::string* p = traits_t::allocate(alloc, 2); // space for 2 strings
traits_t::construct(alloc, p, "foo");
traits_t::construct(alloc, p + 1, "bar");
std::cout << p[0] << ' ' << p[1] << '\n';
traits_t::destroy(alloc, p + 1);
traits_t::destroy(alloc, p);
traits_t::deallocate(alloc, p, 2);
}
}
结果:
7
foo bar
new/delete
new 会分配一块内存空间,并调用构造函数对这块空间进行初始化。
delete 会首先调用对象的析构函数,然后再释放空间。
placement new
placement new 允许在已分配给给定变量的内存上“构造”对象。它可以更快地不重新分配和重用已经分配给它的相同内存.
// class defined
class Foo
{
char cc;
float f;
public:
void print() { std::cout << "ADDR: " << this << std::endl; }
void set_f( float _f ) { std::cout << "set f val : " << _f << std::endl; f = _f; }
void get_f() { std::cout << "get f val : " << f << std::endl; }
};
// allocate mem
char* buff = new char[sizeof(Foo) * N];
memset( buff, 0, sizeof(Foo)*N );
// construct object in mem
Foo* pfoo = new (buff)Foo;
// use object
pfoo->print();
pfoo->set_f(1.0f);
pfoo->get_f();
// destruct object
pfoo->~Foo();
// fre mem
delete [] buff;
自定义定长模版内存池
定义
class MemoryPool
{
public:
MemoryPool(): ptr(mem)
{
}
void* allocate(int mem_size)
{
assert((ptr + mem_size) <= (mem + sizeof mem) && "Pool exhausted!");
void* mem = ptr;
ptr += mem_size;
return mem;
}
private:
MemoryPool(const MemoryPool&);
MemoryPool& operator=(const MemoryPool&);
char mem[4096];
char* ptr;
};
使用
MemoryPool pool;
// Allocate an instance of `Foo` into a chunk returned by the memory pool.
Foo* foo = new(pool.allocate(sizeof(Foo))) Foo;
...
// Invoke the dtor manually since we used placement new.
foo->~Foo();