C++ new 解析重载
C++ new 解析重载
new的三种形式:
(1)operator new(运算符new)
(2)new operator(new 操作)
(3)placement new(特殊的new操作)(不分配内存 + 构造函数的调用)
operator new
重载时体现运算符new
++++++++++++++++++++++++++++++++++++++++++++++++++++++
void * opertor new (size_t size ,const char * file ,long line)
{
cout << file << “:” << line << endl;
void *p = malloc(size);
return p
}
+++++++++++++++++++++++++++++++++++++++++
(1)只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则如果有new_handler,则调用new_handler,否则如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则返回回0
(2) 可以被重载
(3) 重载时,返回类型必须声明为void*
(4) 重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t
(5) 重载时,可以带其它参数
new operator
String *str = new String(”hello”);
(1) 调用operator new分配足够的空间,并调用相关对象的构造函数 .
(2) 不可以被重载(作为运算符,new和sizeof一样,是C++内置的,你不能对它做任何的改变,除了使用它。)
palacement new
在已经分配的内存(可以是堆或者栈)上重新分配空间,但不会分配新的空间,只是构造函数的调用。
+++++++++++++++++++++++++++++++++++++++++
void * operator new(size_t size,void *p)
{
return p;
}
cahr buffer[1024]
Test *p2 = new(buffer) Test(200);//operator new(sizo_t ,void *p)
cout << p2->n_ <
+++++++++++++++++++++++++++++++++++++++++
C++ new 解析重载
最常用的是作为运算符的new,比如:
string *str = new string(“test new”);
作为运算符,new和sizeof一样,是C++内置的,你不能对它做任何的改变,除了使用它。
new会在堆上分配一块内存,并会自动调用类的构造函数。
C++ new用法之二 new函数
第二种就是new函数,其实new运算符内部分配内存使用的就是new函数,原型是:
void *operator new(size_t size);
new函数返回的是一个void指针,一块未经初始化的内存。如你所见,这和C语言的malloc行为相似,你可以重载new函数,并且增加额外的参数,但是必须保证第一个参数必须是size_t类型,它指明了分配内存块的大小,C++允许你这么做,当然一般情况下这是不必要的。如果重载了new函数,在使用new操作符时调用的就是你重载后的new函数了。
如果使用new函数,和语句string *str = new string(“test new”)相对的代码大概是如下的样子:
- string *str = (string*)operator new(sizeof(string));
- str.string(“test new”);
- // 当然这个调用时非法的,但是编译器是没有这个限制的
这还不算完,还有第三种的new存在。
C++ new用法之三 placement new
第三种,placement new,这也是new作为函数的一种用法,它允许你在一块已存在的内存上分配一个对象,而内存上的数据不会被覆盖或者被你主动改写,placement new同样由new操作符调用,调用格式是:
new (buffer) type(size_t size);
先看看下面的代码:
- char str[22];
- int data = 123;
- int *pa = new (&data) int;
- int *pb = new (str) int(9);
结果*pa = 123(未覆盖原数据),而*pb = 9(覆盖原数据),可以看到placement new 并没有分配新的内存,也可以使用在栈上分配的内存,而不限于堆。
为了使用placement new 你必须包含<new>或者<new.h>
其实placement new和第二种一样,只不过多了参数,是函数new的重载,语法格式为:
void *operator new(size_t, void* buffer);
它看起来可能是这个样子:
void *operator new(size_t, void* buffer) { return buffer;}
和new对应的就是delete了,需要回收内存啊,不然就泄漏了,这个下次再写吧,回忆一下今天的内容先。
总结
1. 函数new
void *operator new(size_t size); 在堆上分配一块内存,和placement new(void *operator new(size_t, void* buffer)); 在一块已经存在的内存上创建对象,如果你已经有一块内存,placement new会非常有用,事实上,它STL中有着广泛的使用。
2. 运算符new
最常用的new,没什么可说的。
3. 函数new不会自动调用类的构造函数,因为它对分配的内存类型一无所知;而运算符new会自动调用类的构造函数。
4. 函数new允许重载,而运算符new不能被重载。
5. 紧接着就是对应的delete。
new的六种重载形式
p = new P();
这样的代码的时候, 实际上有两步操作, 首先分配内存,
然后在分配好的内存之上初始化类成员.
第二步是有构造函数完成的, 第一步就是new函数的工作.
全局的new有六种重载形式,
void *operator new(std::size_t count)
throw(std::bad_alloc); //一般的版本
void *operator new(std::size_t count, //兼容早版本的new
const std::nothrow_t&) throw(); //内存分配失败不会抛出异常
void *operator new(std::size_t count, void *ptr) throw();
//placement版本
void *operator new[](std::size_t count) //
throw(std::bad_alloc);
void *operator new[](std::size_t count, //
const std::nothrow_t&) throw();
void *operator new[](std::size_t count, void *ptr) throw();
所以, 刚才的用法, 就是使用new函数的一种重载形式.
如果A这个对象以同样实行重载了new函数的化, 作为成员函数
会被优先调用.
C++的各种new简介
1.new T
第一种new最简单,调用类的(如果重载了的话)或者全局的operator new分配空间,然后用
类型后面列的参数来调用构造函数,用法是
new TypeName(initial_args_list). 如果没有参数,括号一般可以省略.例如
int *p=new int;
int *p=new int(10);
int *p=new foo("hello");
通过调用delete来销毁:
delete p;
2. new T[]
这种new用来创建一个动态的对象数组,他会调用对象的operator new[]来分配内存(如果
没有则调用operator new,搜索顺序同上),然后调用对象的默认构造函数初始化每个对象
用法:
new TypeName[num_of_objects];
例如
int *p= new int[10];
销毁时使用operator delete[]
3.new()T 和new() T[]
这是个带参数的new,这种形式的new会调用operator new(size_t,OtherType)来分配内存
这里的OtherType要和new括号里的参数的类型兼容,
这种语法通常用来在某个特定的地址构件对象,称为placement new,前提是operator new
(size_t,void*)已经定义,通常编译器已经提供了一个实现,包含<new>头文件即可,这个
实现只是简单的把参数的指定的地址返回,因而new()运算符就会在括号里的地址上创建
对象
需要说明的是,第二个参数不是一定要是void*,可以识别的合法类型,这时候由C++的重载
机制来决定调用那个operator new
当然,我们可以提供自己的operator new(size_,Type),来决定new的行为,比如
char data[1000][sizeof(foo)];
inline void* operator new(size_t ,int n)
{
return data[n];
}
就可以使用这样有趣的语法来创建对象:
foo *p=new(6) foo(); //把对象创建在data的第六个单元上
的确很有意思
标准库还提供了一个nothrow的实现:
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();
就可以实现调用new失败时不抛出异常
new(nothrow) int(10);
// nothrow 是std::nothrow_t的一个实例
placement new 创建的对象不能直接delete来销毁,而是要调用对象的析够函数来销毁对
象,至于对象所占的内存如何处理,要看这块内存的具体来源
4. operator new(size_t)
这个的运算符分配参数指定大小的内存并返回首地址,可以为自定义的类重载这个运算符,
方法就是在类里面声明加上
void *operator new(size_t size)
{
//在这里分配内存并返回其地址
}
无论是否声明,类里面重载的各种operator new和operator delete都是具有static属性的
一般不需要直接调用operator new,除非直接分配原始内存(这一点类似于C的malloc)
在冲突的情况下要调用全局的operator加上::作用域运算符:
::operator new(1000); // 分配1000个字节
返回的内存需要回收的话,调用对应的operator delete
5.operator new[](size_t)
这个也是分配内存,,只不过是专门针对数组,也就是new T[]这种形式,当然,需要时可以
显式调用
6.operator new(size_t size, OtherType other_value)
和operator new[](size_t size, OtherType other_value)
参见上面的new()
需要强调的是,new用来创建对象并分配内存,它的行为是不可改变的,可以改变的是各种
operator new,我们就可以通过重载operator new来实现我们的内存分配方案.
new重载注意事项
C++ new 解析重载的更多相关文章
- c++函数重载---2
原创博客:转载请标明出处:http://www.cnblogs.com/zxouxuewei/ 写在前面: 函数重载的重要性不言而明,但是你知道C++中函数重载是如何实现的呢(虽然本文谈的是C++中函 ...
- C++的函数重载 转
——每个现象后面都隐藏一个本质,关键在于我们是否去挖掘 写在前面: 函数重载的重要性不言而明,但是你知道C++中函数重载是如何实现的呢(虽然本文谈的是C++中函数重载的实现,但我想其它语言也是类似的) ...
- 转载:C#中的泛型
泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具 ...
- C#中的泛型 【转】
C#中的泛型 泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确 ...
- C#泛型(C#_编程指南)CSDN学习整理笔记
1.1. 泛型概述 2.0版C#语言和公共语言运行时(CLR)中增加了泛型.泛型将类型参数的概念引入.NETFramework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定 ...
- C# Generic(转载)
型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具体 ...
- C#中的泛型详解
泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具 ...
- C#—泛型_推迟一切可以推迟的东西
泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具 ...
- C++11 delete和default
Defaulted 函数 C++ 的类有四个特殊成员函数,它们分别是:默认构造函数.析构函数.拷贝构造函数以及拷贝赋值运算符.这些类的特殊成员函数负责创建.初始化.销毁,或者拷贝类的对象. 如果程序员 ...
随机推荐
- angularui 分页
分页组件的使用 <!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> ...
- 从输入 URL 到页面加载完成的过程中都发生了什么
从输入 URL 到页面加载完成的过程中都发生了什么 过程描述 浏览器查找域名对应的 IP 地址: 浏览器根据 IP 地址与服务器建立 socket 连接: 浏览器与服务器通信: 浏览器请求,服务器处理 ...
- Python迭代器,生成器--精华中的精华
1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...
- Twitter的分布式系统中ID生成方法——Snowflake
Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序(方便客户端排序),并且在分布式系统 ...
- Race to 1 概率dp
Race to 1 Time Limit: 10000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu [Submit] ...
- GBDT(MART)概念简介
GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种用于回归的机器学习算法,该算法由 ...
- 使用JS动态修改网页body的背景色
大部分网页默认的背景色为白色,个人感觉比较刺眼,于是写了个JS的脚本去改变body部分的背景色,代码如下: // ==UserScript== // @name ChangeBackgroundCol ...
- PHP常用字符串处理函数
(1)strlen(string) 返回字符串长度 (2)strpos(string,find,begin) 返回find字符串第一次出现的位置(从0开始) string:处理的字符串 find:想找 ...
- web应用程序 前段部分调优
1. 使用瀑布图初步诊断网站性能瓶颈 一般来说,打开一个网页的速度会受到以下几项的影响: 1) 服务器花了太长的时间将.aspx页面的内容转化为html. 2) .aspx页面花了太长的时间从服务器端 ...
- Python自学笔记-生成器(来自廖雪峰的官网Python3)
感觉廖雪峰的官网http://www.liaoxuefeng.com/里面的教程不错,所以学习一下,把需要复习的摘抄一下. 以下内容主要为了自己复习用,详细内容请登录廖雪峰的官网查看. 生成器 通过列 ...