placement new和placement delete(重载new和delete2)

2023-10-30 10:08

本文主要是介绍placement new和placement delete(重载new和delete2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

placement new和placement delete

参考:《Effective C++》

  • placement new和placement delete
    • 1 什么是placement new和placement delete
    • 2 如何使用placement版本的new和delete
    • 3 从内存泄露出发
      • a 什么时候new一个对象会发生内存泄露
      • b 当placement new和placement delete遇到继承
    • 转载请注明出处


(1) 什么是placement new和placement delete

placement new和placement delete已经被纳入了C++标准库中
下面是codeblock库中< new >对于二者的声明。

// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p);
inline void* operator new[](std::size_t, void* __p);// Default placement versions of operator delete.
inline void operator delete  (void*, void*);
inline void operator delete[](void*, void*);

placement版本的new和delete初衷是用于在vector中未使用的空间上创建对象的。

如果不特别说明,我们口中的placement 版本的new和delete指的就是上面的几种。

当然我们也可以自定义一些placement 版本(比如带有log功能的new):

void * operator new(size_t size,std::ostream & logger)
throw(std::bad_alloc);

(2) 如何使用placement版本的new和delete

#include <iostream>
#include <new>#define BUFSIZ 512
char *BUF[BUFSIZ]{0};//申请一片内存int main(){std::cout<<"BUF Addr:"<<BUF<<std::endl;int *p(new (BUF)int[10]);//BUF内分配一块内存给10个int类型的数据std::cout<<"P   Addr:"<<p<<std::endl;for(int i=0;i<10;i++){p[i]=i;}for(int i=0;i<10;i++){std::cout<<p[i]<<"  ";}std::cout<<'\n';return 0;
}

这里写图片描述
上面的例子就是在模拟vector的内存分配:在已有的但是未使用的BUF中分配内存。


(3) 从内存泄露出发

为什么我们需要placement版本的new和delete呢?
答:实际的需要。就像vector的内存处理方式。

我们不如从内存泄漏出发,细说placement版本的new和delete。


(a) 什么时候new一个对象会发生内存泄露?

#include <iostream>
#include <new>
#include <cstdlib>class demo{
public:demo():m_dat(100){throw 1;}//palcement版本的new和deletevoid *operator new(size_t size,std::ostream&logger)throw(std::bad_alloc){return malloc(size);}//非placement版本的new和deltevoid operator delete(void *p)throw(){free(p);}
private:int m_dat;
};int main(){demo *p(new (std::cerr)demo);return 0;
}

当new(std::cerr)demo被调用时,new操作成功并返回一块内存,但是demo的构造函数却抛出了异常。当然C++运行期系统考虑到了这种情况,当该情况发生时,系统会自动调用相应版本的delete正确地释放这块内存。

但是new的版本非常多,系统怎么知道调用那个版本呢?
答:系统会寻找参数个数和类型都与new相同的某个delete(这里指的是额外的参数相同,额外的参数指除了new需要size_t和delete需要void*之外的参数)

所以,我们容易知道,上述代码的内存泄露在:palcement版本的new没有对应的placement版本的delete可供调用,所以系统不做任何操作。

解决方法很简单,重载一个相应的operator delete即可:

class demo{
public:demo():m_dat(100){throw 1;}//palcement版本的new和deletevoid *operator new(size_t size,std::ostream&logger)throw(std::bad_alloc){return malloc(size);}//非placement版本的new和deltevoid operator delete(void *p)throw(){free(p);}//重载相应的placement版本的deletevoid operator delete(void *p,std::ostream&logger)throw(){std::cout<<"Placement operator delete"<<std::endl;free(p);}
private:int m_dat;
};

这样,系统就能够正确地选择new和delete。

所以铭记:重载了new就要重载相应版本的delete


(b) 当placement new和placement delete遇到继承

问题源:任何版本的new和delete重载都会覆盖默认的版本。
默认版本的new和delete有这些:

void *operator new(size_t)throw(std::bad_alloc);
void *operator new(size_t,void*)throw();
void *operator new(size_t,const std::nothrow_t&)throw();

当上述任一版本的new都会被类中的任一版本的new重载所覆盖


上例子:

#include <iostream>
#include <new>
#include <cstdlib>class demo{
public:demo():m_dat(100){throw 1;}//重载自定义版本的newvoid *operator new(size_t size,std::ostream&logger)throw(std::bad_alloc){return malloc(size);}//重载相应的deletevoid operator delete(void *p,std::ostream&logger)throw(){std::cout<<"Placement operator delete"<<std::endl;free(p);}
private:int m_dat;
};int main(){demo *p(new demo);return 0;
}

codeblock的错误:
这里写图片描述


VS2015的错误:
这里写图片描述


我在:重载new和delete的一些规则的特殊规则1中提及:一个类的operator new和operator delete 大都是为了本个类服务的,而不是它的派生类。

所以,当一个类重载了new和delete,它就会覆盖全局的,或是基类的new和delete。有时我们需要将这些版本的(比如基类中的)new和delete在本类中同样可以使用,我们该如何做呢?

*如果没有涉及到继承,而是局部和全局之间的覆盖的话,可以直接使用双冒号(::)来调用全局的new和delete,例如:::operator new(size)

让类支持global版本的new和delete(通过继承和using)

#include <iostream>
#include <new>
#include <cstdlib>class StandardNewDelete{
public:static void *operator new(size_t size)throw(std::bad_alloc){return ::operator new(size);}static void *operator new(size_t size,void *ptr)throw(){return ::operator new(size,ptr);}static void *operator new(size_t size,const std::nothrow_t&nt)throw(){return ::operator new(size,nt);}static void operator delete(void *p)throw(){::operator delete(p);}static void operator delete(void *p,void *ptr)throw(){::operator delete(p,ptr);}static void operator delete(void *p,const std::nothrow_t& nt)throw(){::operator delete(p,nt);}
};class demo:public StandardNewDelete{
public:demo():m_dat(100){}//使该类支持global版本的new和deleteusing StandardNewDelete::operator new;using StandardNewDelete::operator delete;void *operator new(size_t size,std::ostream&logger)throw(std::bad_alloc){return malloc(size);}void operator delete(void *p,std::ostream&logger)throw(){std::cout<<"Placement operator delete"<<std::endl;free(p);}
private:int m_dat;
};int main(){demo *p(new demo);return 0;
}

**转载请注明出处

这篇关于placement new和placement delete(重载new和delete2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/307166

相关文章

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

java线程深度解析(一)——java new 接口?匿名内部类给你答案

http://blog.csdn.net/daybreak1209/article/details/51305477 一、内部类 1、内部类初识 一般,一个类里主要包含类的方法和属性,但在Java中还提出在类中继续定义类(内部类)的概念。 内部类的定义:类的内部定义类 先来看一个实例 [html]  view plain copy pu

string字符会调用new分配堆内存吗

gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。

第二十四章 rust中的运算符重载

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust中的运算符重载 目录 注意一、前言二、基本使用三、常用运算符四、通用约束 一、前言 C/C++中有运算符重载这一概念,它的目的是让即使含不相干的内容也能通过我们自定义的方法进行运算符操作运算。 比如字符串本身是不能相加的,但由于C++中的String重载了运算符+,所以我们就可以将两个字符串进行相加、但实际

C++可以被重载的操作符Overloadable operators

C++允许绝大多数操作符被重载,也就是重新定义操作符实现的功能,这样它们的行为可以被设计出来以适应所有的数据类型,包括类。 以下是C++可以被重载的操作符(Overloadable operators): //四则运算符+ - * / %+= -= *= /= %=//比较运算符> >= == != //赋值运算符= //位操作

c++/《重载操作符》

为什么要对运算符进行重载:         C++预定义中的运算符的操作对象只局限于基本的内置数据类型,但是对于我们自定义的类型(类)是没有办法操作的。但是大多时候我们需要对我们定义的类型进行类似的运算,这个时候就需要我们对这么运算符进行重新定义,赋予其新的功能,以满足自身的需求。 <返回类型说明符> operator <运算符符号>(<参数表>) { <函数体> }

Qt: 详细理解delete与deleteLater (避免访问悬空指针导致程序异常终止)

前言 珍爱生命,远离悬空指针。 正文 delete 立即删除:调用 delete 后,对象会立即被销毁,其内存会立即被释放。调用顺序:对象的析构函数会被立即调用,销毁该对象及其子对象。无事件处理:如果在对象销毁过程中还涉及到信号和槽、事件处理等,直接 delete 可能会导致问题,尤其是在对象正在处理事件时。适用场景:适用于在确定对象已经不再被使用的情况下,并且不涉及异步处理或事件循环中的

List list = new ArrayList();和ArrayList list=new ArrayList();的区别?

List是一个接口,而ArrayList 是一个类。 ArrayList 继承并实现了List。 List list = new ArrayList();这句创建了一个ArrayList的对象后把上溯到了List。此时它是一个List对象了,有些ArrayList有但是List没有的属性和方法,它就不能再用了。而ArrayList list=new ArrayList();创建一对象则保留了A

vue原理分析(六)--研究new Vue()

今天我们来分析使用new Vue() 之前研究时,只是说是在创建一个实例。并没有深入进行研究 在vue的源码中找下Vue的构造函数 function Vue(options) {if (!(this instanceof Vue)) {warn$2('Vue is a constructor and should be called with the `new` keyword');}thi

java基础总结10-面向对象6(方法的重载)

1 方法的重载 方法名一样,但参数不一样,这就是重载(overload)。   所谓的参数不一样,主要有两点:第一是参数的个数不一样,第二是参数的类型不一样。只要这两方面有其中的一方面不一样就可以构成方法的重载了。 package cn.galc.test;public class TestOverLoad {void max(int a, int b) {System.out.prin