C++ 内存分配操作符new和delete详解
重载new和delete
首先借用C++ Primer 5e的一个例子:
string *sp = new string("a value");
string *arr = new string[];
new表达式调用一个名为operator new(或者operator new[])的标准函数,分配一块足够大的,原始的,未命名的内存空间来存储特定的类型或者对象的数组。
编译器运行相应的构造函数以构造这些对象,并且传入初值。
对象构造完毕后返回指向该对象的指针。
delete sp;
delete[]arr;
对sp所指的对象或者arr所指的数组中的元素执行析构函数
然后第二部调用operator delete或者(operator delete[])的标准库来释放掉内存空间。
replaceable allocation functions
void* operator new ( std::size_t count );
void* operator new[]( std::size_t count );
void* operator new ( std::size_t count, std::align_val_t al);(since C++)
void* operator new[]( std::size_t count, std::align_val_t al);(since C++) replaceable non-throwing allocation functions(nothrow版本表示承诺不抛出异常,分配内存失败直接返回null,但是不保证构造函数不抛出异常,没什么使用必要)
void* operator new ( std::size_t count, const std::nothrow_t& tag);
void* operator new[]( std::size_t count, const std::nothrow_t& tag);
void* operator new ( std::size_t count, std::align_val_t al, const std::nothrow_t&);(since C++)
void* operator new[]( std::size_t count, std::align_val_t al, const std::nothrow_t&);(since C++) non-allocating placement allocation functions(注意这两个版本不能重定义, 也就是常见的placement new)
void* operator new ( std::size_t count, void* ptr );
void* operator new[]( std::size_t count, void* ptr ); user-defined placement allocation functions
void* operator new ( std::size_t count, user-defined-args... );
void* operator new[]( std::size_t count, user-defined-args... );
void* operator new ( std::size_t count, std::align_val_t al, user-defined-args... ); (since C++)
void* operator new[]( std::size_t count, std::align_val_t al, user-defined-args... );(since C++) class-specific allocation functions
void* T::operator new ( std::size_t count );
void* T::operator new[]( std::size_t count );
void* T::operator new ( std::size_t count, std::align_val_t al );(since C++)
void* T::operator new[]( std::size_t count, std::align_val_t al );(since C++) class-specific placement allocation functions
void* T::operator new ( std::size_t count, user-defined-args... );
void* T::operator new[]( std::size_t count, user-defined-args... );
void* T::operator new ( std::size_t count, std::align_val_t al, user-defined-args... );(since C++)
void* T::operator new[]( std::size_t count, std::align_val_t al, user-defined-args... );(since C++)
replaceable usual deallocation functions
void operator delete ( void* ptr );
void operator delete[]( void* ptr );
void operator delete ( void* ptr, std::align_val_t al );(since C++)
void operator delete[]( void* ptr, std::align_val_t al );(since C++)
void operator delete ( void* ptr, std::size_t sz );(since C++)
void operator delete[]( void* ptr, std::size_t sz );(since C++)
void operator delete ( void* ptr, std::size_t sz, std::align_val_t al );(since C++)
void operator delete[]( void* ptr, std::size_t sz, std::align_val_t al );(since C++)
replaceable placement deallocation functions(同new,只能保证operator delete不抛出异常,但是不能保证析构不抛出异常)
void operator delete ( void* ptr, const std::nothrow_t& tag );
void operator delete[]( void* ptr, const std::nothrow_t& tag );
void operator delete ( void* ptr, std::align_val_t al, const std::nothrow_t& tag );(since C++)
void operator delete[]( void* ptr, std::align_val_t al, const std::nothrow_t& tag );(since C++)
non-allocating placement deallocation functions(也就是传统意义上的placement delete)
void operator delete ( void* ptr, void* place );
void operator delete[]( void* ptr, void* place );
user-defined placement deallocation functions
void operator delete ( void* ptr, args... );
void operator delete[]( void* ptr, args... );
class-specific usual deallocation functions
void T::operator delete ( void* ptr );
void T::operator delete[]( void* ptr );
void T::operator delete ( void* ptr, std::align_val_t al );(since C++)
void T::operator delete[]( void* ptr, std::align_val_t al );(since C++)
void T::operator delete ( void* ptr, std::size_t sz );
void T::operator delete[]( void* ptr, std::size_t sz );
void T::operator delete ( void* ptr, std::size_t sz, std::align_val_t al );(since C++)
void T::operator delete[]( void* ptr, std::size_t sz, std::align_val_t al );(since C++)
class-specific placement deallocation functions
void T::operator delete ( void* ptr, args... );
void T::operator delete[]( void* ptr, args... );
non-allocating placement allocation functions(注意这两个版本不能重定义, 也就是常见的placement new)
void* operator new ( std::size_t count, void* ptr );
void* operator new[]( std::size_t count, void* ptr ); non-allocating placement deallocation functions(也就是传统意义上的placement delete)
void operator delete ( void* ptr, void* place );
void operator delete[]( void* ptr, void* place );
new (place_address) type
new (place_address) type (initializers)
new (place_address) type [size]
new (place_address) type [size]{ braced initializer list }
template <class _T1>
inline void _Construct(_T1* __p) {
new ((void*) __p) _T1();
}
template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
__pointer->~_Tp();
}
class Widget
{
public:
Widget(int i) :m_haha(i) { throw std::exception(); }
static void *operator new(std::size_t size, std::ostream& logStream);
static void operator delete(void *pMemory)
{
::operator delete(pMemory);
}
static void operator delete(void *pMemory, std::ostream& logStream);
private:
int m_haha;
};
void *Widget::operator new(std::size_t size, std::ostream& logStream)
{
cout << "Hello World" << std::endl;
while (true)
{
auto p = malloc(size);
if (p)
return p; auto h = get_new_handler();
if (!h)
h();
else
throw std::bad_alloc();
}
}
void Widget::operator delete(void *pMemory, std::ostream& logStream)
{
cout << "Hello World delete" << std::endl;
::delete pMemory;
}
int main()
{
try
{
Widget *k = new (std::cout) Widget();
delete k;
}
catch (const std::exception&)
{
}
return ;
}
class DerivedWidget : public Widget
{
public:
using Widget::operator delete;
using Widget::operator new;
static void *operator new(std::size_t size, const std::nothrow_t nt);
static void operator delete(void *pMemory, const std::nothrow_t nt);
};
当operator new无法申请到所需内存时,我们可以调用所谓的new_handler,在标准库中有以下内容:
typedef void (__CLRCALL_PURE_OR_CDECL * new_handler) ();
#endif /* !defined(_INC_NEW) || !defined(_MSC_EXTENSIONS) */
// FUNCTION AND OBJECT DECLARATIONS
_CRTIMP2 new_handler __cdecl set_new_handler(_In_opt_ new_handler)
_THROW0(); // establish alternate new handler
_CRTIMP2 new_handler __cdecl get_new_handler()
_THROW0(); // get current new handler
_STD_END
让更多内存可被使用
安装另一个new-handler(如果当前的new-handler无法获取更多的内存,可以用另一个代替)
卸载new-handler
抛出bad_alloc(或者派生自此异常的其他异常),让异常传播到其他地方
不返回,调用abort或者exit
template<typename T>
class NewHandlerSupport
{
public:
NewHandlerSupport() = default;
explicit NewHandlerSupport(std::new_handler h):_handler(h) { }
~NewHandlerSupport() { std::set_new_handler(_handler); }
static void *operator new(std::size_t size) { ::operator new(size); }
static void *operator new(std::size_t size, std::ostream& logStream);
static void operator delete(void *pMemory) { ::operator delete(pMemory); }
static void operator delete(void *pMemory, std::ostream& logStream);
static std::new_handler set_new_handler(std::new_handler p)noexcept;
private:
std::new_handler _handler;//拿来临时替换的
static std::new_handler _currnentHandler;
NewHandlerSupport(NewHandlerSupport &&) = default;
NewHandlerSupport(const NewHandlerSupport &) = delete;
NewHandlerSupport& operator=(const NewHandlerSupport &) = delete;
};
template<typename T>
std::new_handler NewHandlerSupport<T>::set_new_handler(std::new_handler p)noexcept
{
std::new_handler oldHandler = _currnentHandler;
_currnentHandler = p;
return oldHandler;
}
template<typename T>
void NewHandlerSupport<T>::operator delete(void *pMemory, std::ostream& logStream)
{
cout << "Hello World delete" << std::endl;
::delete pMemory;
}
template<typename T>
void * NewHandlerSupport<T>::operator new(std::size_t size, std::ostream& logStream)
{
NewHandlerSupport h(std::set_new_handler(_currnentHandler));
cout << "Hello World" << std::endl;
return ::operator new(size);
}
template<typename T>std::new_handler NewHandlerSupport<T>::_currnentHandler = ;
class Widget : public NewHandlerSupport<Widget>
{
public:
Widget(int i) :m_haha(i) { }
private:
int m_haha;
};
Widget::set_new_handler(error);
Widget *k = new (std::cout) Widget();
delete k;
我们经常说C++的内存管理(new和delete)和C的(malloc和free)最大的不同是,C++分配的内存是在自由存储区,而C则是在堆区,至于堆区就是现代操作系统给进程分配的内存空间的一部分,看下面的图。
void* __CRTDECL operator new(size_t const size)
{
00007FF74DC58630 mov qword ptr [rsp+],rcx
00007FF74DC58635 sub rsp,38h
for (;;)
{
if (void* const block = malloc(size))
00007FF74DC58639 mov rcx,qword ptr [size]
00007FF74DC5863E call malloc (07FF74DC513FCh)
00007FF74DC58643 mov qword ptr [rsp+20h],rax
00007FF74DC58648 cmp qword ptr [rsp+20h],
00007FF74DC5864E je operator new+27h (07FF74DC58657h)
{
return block;
00007FF74DC58650 mov rax,qword ptr [rsp+20h]
00007FF74DC58655 jmp operator new+4Bh (07FF74DC5867Bh)
}
if (_callnewh(size) == )
00007FF74DC58657 mov rcx,qword ptr [size]
00007FF74DC5865C call _callnewh (07FF74DC516B8h)
00007FF74DC58661 test eax,eax
00007FF74DC58663 jne operator new+49h (07FF74DC58679h)
{
if (size == SIZE_MAX)
00007FF74DC58665 cmp qword ptr [size],0FFFFFFFFFFFFFFFFh
00007FF74DC5866B jne operator new+44h (07FF74DC58674h)
{
__scrt_throw_std_bad_array_new_length();
00007FF74DC5866D call __scrt_throw_std_bad_array_new_length (07FF74DC51604h)
}
else
00007FF74DC58672 jmp operator new+49h (07FF74DC58679h)
{
__scrt_throw_std_bad_alloc();
00007FF74DC58674 call __scrt_throw_std_bad_alloc (07FF74DC5120Dh)
}
}
// The new handler was successful; try to allocate again...
}
00007FF74DC58679 jmp operator new+9h (07FF74DC58639h)
}
void __CRTDECL operator delete(void* const block) noexcept
{
00007FF74DC586A0 mov qword ptr [rsp+],rcx
00007FF74DC586A5 sub rsp,28h
#ifdef _DEBUG
_free_dbg(block, _UNKNOWN_BLOCK);
00007FF74DC586A9 mov edx,0FFFFFFFFh
00007FF74DC586AE mov rcx,qword ptr [block]
00007FF74DC586B3 call _free_dbg (07FF74DC5119Ah)
#else
free(block);
#endif
}
std::allocator<string> alloc;
auto p = alloc.allocate();
alloc.construct(p, "fuck");
C++ 内存分配操作符new和delete详解的更多相关文章
- C++ 内存分配(new,operator new)详解
参考:C++ 内存分配(new,operator new)详解 如何限制对象只能建立在堆上或者栈上 new运算符和operator new() new:指我们在C++里通常用到的运算符,比如A* a ...
- 【转】C++ 内存分配(new,operator new)详解
本文主要讲述C++ new运算符和operator new, placement new之间的种种关联,new的底层实现,以及operator new的重载和一些在内存池,STL中的应用. 一 new ...
- 动态内存分配(new)和释放(delete)
在之前我们所写过的程序中,所必需的内存空间的大小都是在程序执行之前就已经确定了.但如果我们需要内存大小为一个变量,其数值只有在程序运行时 (runtime)才能确定,例如有些情况下我们需要根据用户输入 ...
- c++内存分配(new和delete)
c中malloc和free是函数,包含在stdlib.h头文件中,分配成功返回指针,失败返回空指针. 与new的区别是: 1,malloc与free是C++/C语言的标准库函数,new/delete是 ...
- 深入C语言内存区域分配(进程的各个段)详解(转)
原文地址:http://www.jb51.net/article/39696.htm 一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务) ...
- [转]深入C语言内存区域分配(进程的各个段)详解
一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务)在存储(没有调入到内存运行)时拥有3个部分,分别是代码段(text).数据段(data ...
- malloc/free和new/delete详解与应用
C++面试经常会问到关于malloc/free和new/delete的区别,网上有不同版本的解释,这里总结下并加上个人理解和使用. 两者相同点 1.都可以申请动态堆内存. 两者不同点 1.new/de ...
- Linux 内存映射函数 mmap()函数详解
mmap将一个文件或者其它对象映射进内存.文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零.mmap在用户空间映射调用系统中作用很大.头文件 <sys/ ...
- C++ new/delete详解及原理
学了冯诺依曼体系结构,我们知道: 硬件决定软件行为,数据都是围绕内存流动的. 可想而知,内存是多么重要.当然,我们这里说的内存是虚拟内存(详情看Linxu壹之型). 1.C/C++内存布局 2.C语言 ...
随机推荐
- 洛谷P3405 [USACO16DEC]Cities and States省市
P3405 [USACO16DEC]Cities and States省市 题目描述 To keep his cows intellectually stimulated, Farmer John h ...
- 洛谷 P2216 [HAOI2007]理想的正方形
P2216 [HAOI2007]理想的正方形 题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一 ...
- Spring Boot Dubbo 构建分布式服务
概述: 节点角色说明 节点 角色说明 Provider 暴露服务的服务提供方 Consumer 调用远程服务的服务消费方 Registry 服务注册与发现的注册中心 Monitor 统计服务的调用次数 ...
- Acwing 98-分形之城
98. 分形之城 城市的规划在城市建设中是个大问题. 不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现. 而这座名为 Fractal 的城市设想了这样 ...
- mysql5.7安装部署后初始密码查看以及修改
一.查看初始密码以下两种方法: 1.找到自己的error.log日志文件,执行自己的命令,红色标记的部分为初始化密码. grep 'temporary password' /data/mysql/er ...
- G.Longest Palindrome Substring
链接:https://ac.nowcoder.com/acm/contest/908/G 题意: A palindrome is a symmetrical string, that is, a st ...
- js解析url参数
1.采用正则,这也是现在使用最为方便的 function getQueryString(name) { const reg = new RegExp("(^|&)" + n ...
- MVC的viewPage 通用属性运用。
试想下在MVC的前端页面JS或者html中需要使用多语言,而后端的多语言是维护在资源文件中的,前端如果使用的话需要使用AJAX频繁的获取,一个页面中可能会存在大量的需要语言转换的地方,频繁使用AJAX ...
- JAVA基础之Map接口
个人理解: 个人感觉Map接口以后会经常用到,可以很清晰地查找某个对象,要熟悉其四种遍历方法.特别注意其键值对的键不能是重复的,有想定义有序存取的话,可以使用LinkedHashMap集合.不过定义自 ...
- css3相关样式
1.渐变 1.1 线性渐变(Linear Gradients)- 向下/向上/向左/向右/对角方向 background: linear-gradient(direction, color-stop1 ...