本文目录

专业名称

new operator:new操作符,new表达式

operator new:new运算符

placement new:定位new

delete operator:delete操作符,delete表达式

operator delete:delete运算符

delete没有placement版本 各个版本的解释 1. new operator

new operator:new表达式

实际上只是一个称呼,是三个操作的集合。

  • 申请内存(调用operator new)
  • 在内存上调用构造函数
  • 将申请的内存空间返回

delete operator:delete表达式

delete operator也是一个称呼,是两个操作的集合。

  • 调用析构函数
  • 调用operator delete释放空间

operator new/delete:new/delete运算符

  • 分为::operator new与Class::operator new。一个是全局的,一个是类内部定义的。平时听到的new与delete重载,就是重载这里的new/delete。注意点如下。

    -- class中的new与delete是隐式静态的。也就是不管你有没有声明为static,它都是static的。

    -- 非static成员在没有实例存在的情况下是不能使用的。而当我们定义一个实例时,很明显此时实例还没有存在,这个时候不可能调用一个非static的成员,所以operator new/delete必须是static的。

    -- static成员是不会隐式传入this指针的,所以在operator new/delete中不能使用任何类的非静态成员。

    -- 非静态的成员函数在编译器会在argument list的第一个位置插入一个本身类型的this指针。所以一个函数名,参数列表与全局函数一模一样的函数,也不会出现二义性问题。但是一个static成员函数,是不会隐私插入this指针的,所以当我们在class中重载new/delete时,客户定义实例时需要确认是否在全局也定义了new,否则会产生二义性。举个栗子。
//VS2013
class StringClass
{
public:
void *operator new(size_t size);
};
void *operator new(size_t size);
void main()
{
//1. 调用operator new申请内存
//2. 调用构造函数
//二义性,同时存在两个可用的operator new
StringClass *p = new StringClass;
}

-- PS:关于函数匹配规则,一开始接触觉得很简单,当某天触发了bug的时候就会“书到用时方恨少”,这方面推荐两个连接给大家。看这里还有这里

  • 关于operator new/delete标准库提供了8个版本,这些版本的new/delete我们都是可以重载的。如下。
//八个版本中有2个new版本有可能抛出异常
void* operator new(size_t t);
void* operator new[](size_t t);
void* operator delete(void*)noexcept;
void* operator delete[](void*)noexcept; //nothrow_t为空结构体,用于区分上面与下面运算符
void* operator new(size_t t,nothrow_t&)noexcept;
void* operator new(size_t t,nothrow_t&)noexcept;
void* operator delete(void *,nothrow_t&)noexcept;
void* operator delete[](void *,nothrow_t&)noexcept;

理论这么多,下面先来个栗子。

//StringClass.h
//自己定义的一个类
#pragma once
#include<iostream>
using namespace std;
class StringClass
{
public:
StringClass(){
cout << "string class construtor" << endl;
}
~StringClass(){
cout << "string class destrutor" << endl;
}
void *operator new(size_t size){
cout << "Class::operator new(size_t) " << size << endl;
void *ret = (void*)malloc(size);
return ret;
}
static void operator delete(void *p){
free(p);
cout << "Class::operator delete(void*)" << endl;
}
};
void main(){
StringClass *p = new StringClass;
delete p;
}

结果如下。在new表达式中,先调用了operator new,再调用constructor,最后将指针返回给p。最后在释放的时候,先调用了destructor,再调用了operator delete。

既然使用到了delete,怀着“授人以鱼不如授人以渔”的想法,推荐读者了解一下crtdbg这个头文件,谷歌一下就知道了。

placement new:定位new

  • 在堆里面申请内存,需要寻找空的内存,多次申请释放还会产生大量的内存碎片,但这个神器会帮你解决这些问题。使用它,你只需要申请一次内存,就能够多次创建不同的实例,具体参见下例的讲解。
  • 前面提到,new operator会有三个步骤,第一是申请内存,第二是调用构造函数,第三是返回指针。定位new,之所以为定位,是因为我们事先分配好了内存,并且指定了必须使用这块内存进行初始化。共有四种语法如下。
new (place_address) type;
new (place_address) type (initializers);
new (place_address) type[size];
new (place_address) type[size]{braced initializers list};

对第一种我们举个栗子。

#pragma once
#include<iostream>
using namespace std; class StringClass
{
public:
StringClass(){
cout << "string class construtor" << endl;
}
~StringClass(){
cout << "string class destrutor" << endl;
}
//比起前面的代码,增添了这个函数
static void *operator new(size_t size, void *p) {
cout << "Class::operator new(size_t,void*)" << endl;
return p;
}
}; void main()
{
StringClass *buf = (StringClass*)malloc(sizeof(StringClass));
memset(buf, 0, sizeof(StringClass));
StringClass *p2 = new(buf) StringClass();
p2->~StringClass();
free(buf);
}
  • 上面总共有五个步骤:

    -- 上述代码先使用申请了一块内存,大小用户根据自己需要去决定。

    -- 初始化这块内存。

    -- 然后在上面调用了StringClass的构造函数,再令p2指向他。

    -- 然后p2使用完毕在上面调用自己的析构函数。

    -- 程序结束前将这块内存释放。假如有需要创建另外一个对象,我们可以不用申请新的内存,继续使用这块内存。

  • 与operator new不同的是,使用placement new是无需定义operator delete的,如上,整个过程压根就没有用到它。相反,假如你在客户端使用了它,还会导致调用析构函数的多次调用。

警告

除了placement new外,其他版本的new与delete都要成对地重载。因为你重载了编译器的new,它不知道delete需要为你做些什么。

总结

  • new总共分成3类,new operator是一个操作的集合,不是具体的运算符。可以重载的叫做operator new。
  • 使用了placement new,必须定义void *operator new(siez_t,void *p),不用定义operator delete。而除了placement new,若定义了operator new/delete需要成对定义。
  • 所有的operator new都是隐式静态的,为了让代码易于阅读,你应该加上static
  • 所有的operator new都应该返回void*

最后的疑问

在很多书籍以及博客中,都指出了下面这个operator new不能被重载。在C++Primer第五版,白色封面的那本,P727最下方中,明确指出了它不能重载,但实际上,使用placement new的时候我们却不得不重载这个版本。关于这一点,希望有高人能够给出意见

C++基础——new与delete的更多相关文章

  1. Python3 tkinter基础 Entry insert delete 点击按钮 向输入框赋值 或 清空

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  2. C++基础 new和delete

    1.new delete 的使用 (1)基本数据类型 ); delete p; int *p = (int *)malloc(sizeof(int)); *p = ;free(p); (2)数组 ]; ...

  3. 关于delete和delete[]

    [精彩] 求问delete和delete[] 的区别??http://www.chinaunix.net/jh/23/311058.html C++告诉我们在回收用 new 分配的单个对象的内存空间的 ...

  4. 【转】清理Kylin的中间存储数据(HDFS & HBase Tables)

    http://blog.csdn.net/jiangshouzhuang/article/details/51290399 Kylin在创建cube过程中会在HDFS上生成中间数据.另外,当我们对cu ...

  5. Memcached详解

    Memcached介绍 Memcached是什么? Free & open source, high-performance, distributed memory object cachin ...

  6. MySQL auto_increment_increment 和 auto_increment_offset

    参考这一篇文章:(不过我对这一篇文章有异议) http://blog.csdn.net/leshami/article/details/39779509 1:搭建测试环境 create table t ...

  7. SQL Server中一些有用的日期sql语句

    SQL Server中一些有用的日期sql语句 1.一个月第一天的 SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0) 2.本周的星期一 SELECT DA ...

  8. 02 DML(DataManipulationLanguage)

    1.插入记录     基本语法 :         INSERT INTO tbl_name (col_name ,col_name1,..,col_nameN) VALUES (val1,val2, ...

  9. 转载:STL四种智能指针

    转载至:https://blog.csdn.net/K346K346/article/details/81478223 STL一共给我们提供了四种智能指针: auto_ptr.unique_ptr.s ...

随机推荐

  1. C# 获取SQL Server所有的数据库名称

    参考文章:http://www.cnblogs.com/Abel_cn/archive/2008/12/09/1351425.html http://blog.csdn.net/friendan/ar ...

  2. WPF基础学习笔记整理 (八) 命令

    基础知识: 命令是应用程序的任务,并跟踪任务是否能够被执行. 命令不包含执行应用程序任务的代码. 命令是比事件更高级的元素.默认的命令目标是当前获得焦点的元素. 良好的Win应用程序,应用程序逻辑不应 ...

  3. Python 以指定宽度格式化输出

    当对一组数据输出的时候,我们有时需要输出以指定宽度,来使数据更清晰.这时我们可以用format来进行约束 mat = "{:20}\t{:28}\t{:32}" print(mat ...

  4. django 数据库同步

    python manage.py makemigrations python manage.py migrate

  5. shell 跳出循环

    跳出循环 break命令 例: #!/bin/bash while : do echo -n "输入 1 到 5 之间的数字:" read aNum case $aNum in 1 ...

  6. shell 浮点运算

    浮点运算 let 和 expr 都无法进行浮点运算,但是 bc 和 awk 可以. 范例:求 除以 ,保留 位有效数字 $ echo "scale=3; 1/13" | bc . ...

  7. Codeforces 349B - Color the Fence

    349B - Color the Fence 贪心 代码: #include<iostream> #include<algorithm> #include<cstdio& ...

  8. Codeforces 757B - Bash's Big Day(分解因子+hashing)

    757B - Bash's Big Day 思路:筛法.将所有因子个数求出,答案就是最大的因子个数,注意全为1的特殊情况. 代码: #include<bits/stdc++.h> usin ...

  9. Asp.Net MVC中Action跳转

    首先action的跳转大致归类: 1跳转到与当前同一控制器内的action和不同控制器内的action. 2带有参数的action跳转和不带参数的action跳转. 3跳转到指定视图,不经过Contr ...

  10. 20170711筛选OutLook主题并转发

    Sub 筛选OutLook主题并转发() On Error Resume Next Dim OutApp As Application Set OutApp = Application Dim Out ...