Halo
发布于 2022-05-16 / 130 阅读 / 0 评论 / 0 点赞

c++内存管理

内存分配

头文件

内存分配的头文件都在 <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();

评论