c++ 源码 之 标准库new , operator new , placement new , array new

在c++中管理内存的一些手段与细节

那么这篇博客的内容主要是在学习了jjhou老师的内存管理后我自己总结的一些知识点,关于侯捷老师的内存管理的内容可以自己搜索那么直接进入正题了

1.new和operator new

依照bjarne的c++ programming language的11.2.3章节所说,new ,delete,operator new,operator delete的实现在< new >头文件中

那么在gcc的文件中确实含有new的头文件内容确实也有 operator new的声明

void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc)
  __attribute__((__externally_visible__));
void* operator new[](std::size_t) _GLIBCXX_THROW (std::bad_alloc)
  __attribute__((__externally_visible__));
void operator delete(void*) _GLIBCXX_USE_NOEXCEPT
  __attribute__((__externally_visible__));
void operator delete[](void*) _GLIBCXX_USE_NOEXCEPT
  __attribute__((__externally_visible__));

说明一下 new的时候发生什么

首先调用operator new函数 (此函数可以重载达到自己分配内存的目的)

然后将指针转换为 obj 的对应类型

最后调用对象的 构造函数

如果失败 抛出bad_alloc异常

那么 operator new 到底做了些什么呢? 在gcc的 new_op.cc文件中
我们找到了 operator new 的源码

//头文件先忽略
using std::new_handler;
using std::bad_alloc;// using 声明
#if _GLIBCXX_HOSTED// 如果 有这个宏使用 std的malloc
using std::malloc;
#else// 没有则使用c语言的malloc
// A freestanding C runtime may not provide "malloc" -- but there is no
// other reasonable way to implement "operator new".
extern "C" void *malloc (std::size_t);
#endif

_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
  void *p;
  // new_handler 以后说明,但是可以看出首先我们根据入口参数 sz的大小分配内存, 
  // 如果sz为0 则令其为1 ,然后在while循环中调用malloc申请内存
  // 直到 申请成功 或者 抛出异常或者 abort
  /* malloc (0) is unpredictable; avoid it.  */
  if (sz == 0)
    sz = 1;

  while (__builtin_expect ((p = malloc (sz)) == 0, false))
    {
      new_handler handler = std::get_new_handler ();
      if (! handler)
    _GLIBCXX_THROW_OR_ABORT(bad_alloc());
      handler ();
    }

  return p;
}

所以 new expression 调用了operator new函数 而operator 调用了malloc函数

再来看对应的delete(这里只放简化的代码)

operator delete(void* ptr) _GLIBCXX_USE_NOEXCEPT
{
  std::free(ptr);
}

所以new与malloc的区别也很明显了

new 的过程是
//调用 operator new 函数
1. void * tmp_point = ::operator new( sizeof( obj ) ) ;
// 更改 指针的属性
2. obj * point = static_cast

2.placement new

先找源码 内容在 < new > 头文件当中

// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
{ return __p; }

可以看到 placement new 什么内存都没有申请 只是直接返回 指针
那么placement new的步骤和new的步骤像只是没有申请任何的内存但是调用了构造函数

当我们使用
obj p = new( alreadyExistPoint )obj()
意味着在已经分配内存的 内容里调用obj的构造函数
那么步骤是这样的
//调用 重载的 operator new 函数
1. void * tmp_point = ::operator new( sizeof( obj ) ,alreadyExistPoint) ;
// 更改 指针的属性
2. obj * point = static_cast

// Default placement versions of operator delete.
//实现没有找到 但是原理一定类似于 operator delete 只是被重载了而已
inline void operator delete  (void*, void*) _GLIBCXX_USE_NOEXCEPT { }

3.array new

先上源码

_GLIBCXX_WEAK_DEFINITION void*
operator new[] (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
  return ::operator new(sz);
}

这里是我自己有疑问的地方

我们知道array new是对new了一个数组的对象,并且调用其中的默认构造函数

而且array new必须和array delete成对的使用,但是源码部分没有展示出对象多次调用构造函数
这部分内容仍然需要我实力再进一步才能解答

你可能感兴趣的:(源码)