new在C++中是一个我们经常用到的运算符。由它所创建的变量会被分配在堆中,并且在程序结束之前应当将分配的内存delete掉,否则就会导致内存泄漏。但是除此之外,你对new有更深入的了解吗?本篇文章将深入探讨C++中的new运算符,我在这篇文章中总结了new的以下知识点:
1. new内存分配失败后的处理
如果你认为new分配失败后应当如以下代码处理:
int*p=new int;
if(!p)
{
//error processing
}
那么你就大错特错了。C++中规定当new分配失败时,它会抛出一个bad_alloc exception,此时应当采用异常处理的方法:
try
{
int* pStr=new string[SIZE];
}
catch(const bad_alloc& e)
{
//error processing
}
2. new的三种形态。
new实际上有三种形态:new operator、operator new和placement new。
new operator是我们最常用的形态(用法如上文的代码所示),它是语言内建的,不能重载,也不能改变其行为。它在执行过程中,与其余的两种形态都发生了密切的关系:第一步通过operator new来实现内存申请,第二步通过placement new来调用构造函数。
operator new在默认情况下为调用分配内存的代码,尝试从堆上得到一段空间,如果分配成功则直接返回,分配失败则调用new_handler函数,然后继续重复前面的过程,直到抛出了异常为止。如下的代码便重载了A的operator new函数:
class A
{
public:
A(int a);
~A();
void* operator new(size_t size);
} void* A::operator new(size_t size)
{
cout<<"A's operator new"<<endl;
return ::operator new(size);
}
这里调用了全局的new来进行内存分配。
placement new则是决定在分配的空间里采用哪种构造函数。通常情况下,构造函数是由编译器自动调用的,但你也可以手动调用构造函数。如以下代码所示:
#include <iostream>
class X
{
public:
X() { std::cout << "constructor of X" << std::endl; }
~X() { std::cout << "destructor of X" << std::endl; } void SetNum(int n)
{
num = n;
} int GetNum()
{
return num;
} private:
int num;
}; int main()
{
char* buf = new char[sizeof(X)];
X *px = new(buf)X;
px->SetNum(10);
std::cout << px->GetNum() << std::endl;
px->~X();
delete[]buf; return 0;
}
当然,如果显示地调用placement new,那么也得显示地调用对应的placement delete。
placement new的意义在于,operator new开辟内存是比较花费时间的,因此你可以一次用operator new开辟一片内存,然后利用placement new重复地在这片内存上构建对象,这样可以省去很多时间。
3. new_handler函数
在使用operator new申请内存失败之后, 编译器会调用new_handler函数来进行相应的处理。你可以定制属于自己的new_handler函数,只需要调用<new>中的set_new_handler之中即可,set_new_handler的参数为一个函数指针,返回值为指向的是set_new_handler调用之前的异常处理函数。
我们也可以根据类设定不同的new_handler函数,以下是一个例子:
class A
{
public:
static std::new_handler set_new_handler(std::new_handler p)throw();
static void * operator new(std::size_t size) throw(std::bad_alloc);
static void MemoryErrorHandling(); // new_handler function
private:
static std::new_handler m_curHandler;
};
std::new_handler A::m_curHandler=NULL;
std::new_handler A::set_new_handler(std::new_handler p)throw()
{
std::new_handler old_handler=m_curHandler;
m_curHandler=p;
return old_handler;
} void MemoryErrorHandling()
{
//...
} void *operator new (std::size_t size)throw(std::bad_alloc)
{
set_new_handler(MemoryErrorHandling);
return ::operator new(size);
}
随机推荐
-
配置git密钥,然后新建仓库
Generating SSH keys (打开下面的链接) https://help.github.com/articles/generating-ssh-keys/ 完成配置后 开始在github上 ...
-
C语言面试题(二)
上篇对嵌入式中C语言基本数据类型,关键字和常用操作进行了汇总,这篇我们将侧重字符串操作.请看下面的字符串处理函数: a.库函数 1)将字符串src拷贝到字符数组dest内 c ...
-
sublime Text 3的默认快捷键大全
Ctrl+M 光标跳至对应的括号 Alt+. 闭合当前标签 Ctrl+Shift+A 选择光标位置父标签对儿 Ctrl+Shift+[ 折叠代码 Ctrl+Shift+] 展开代码 Ctrl+KT 折 ...
-
Spring 4.2 annotation event Publisher/Listener
http://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2 Better applicatio ...
-
【转】VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)
原文网址:http://www.jizhuomi.com/software/189.html 上一节鸡啄米讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常 ...
-
typedef用法小结
typedef用法小结- - 注意:本文转自网络,版权归原作者所有. typedef typedef用法小结- - 这两天在看程序的时候,发现很多地方都用到typedef,在结构体定义,还有一些数组等 ...
-
D. Diverse Garland Codeforces Round #535 (Div. 3) 暴力枚举+贪心
D. Diverse Garland time limit per test 1 second memory limit per test 256 megabytes input standard i ...
-
cordova app强制横屏
非常简单,只需要在config.xml里加上这行: <preference name="Orientation" value="landscape" /& ...
-
Java快速排序和归并排序详解
快速排序 概述 快速排序算法借鉴的是二叉树前序遍历的思想,最终对数组进行排序. 优点: 对于数据量比较大的数组排序,由于采用的具有二叉树二分的思想,故排序速度比较快 局限 只适用于顺序存储结构的数据排 ...
-
自定义网站的icon和收藏夹图标
定制网站收藏夹图标的方法有两种: 第一种方法: 第一步,当然是准备一个能体现您的主页的风格和个性的图标.比较简便的办法除了下载,就是将您的网站的logo做成一个图标. 第二步,将这个图标文件命名为:f ...