当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > C++中placement new和delete讨论

C++中placement new和delete讨论 时间:2018-09-27      来源:未知

在程序设计中频繁地进行动态内存分配和释放容易造成内存碎片,给需要长期稳定运行的系统带来了隐患。尽管现代操作系统在内存管理的稳健性上已经有了较大提高,但是动态内存分配的效率、稳定性等问题仍然是一个困扰。所以在需要长期稳定运行的、生命攸关的嵌入式设备程序开发中通常都要避免过多地使用new和delete,甚至禁止使用C++的标准库,因为其中经常进行动态内存的分配与释放。然而要充分享用使用C++带来的便利之处,动态地创建和销毁对象的能力还是非常有必要的。

本文引用地址://emb.hqyj.com/Column/7365.html

通常的new运算符会在堆中动态分配内存,并在成功分配的内存空间上调用相应对象的构造函数,而delete运算符会先在该内存空间上调用相应对象的析构函数,然后释放该内存空间。然而在C++中,可以通过对new和delete的重载来实现特殊的功能。不过在程序员编写的new和delete的重载函数中都只是负责内存空间的分配和释放,编译器会在new时强制调用构造函数,在delete时强制调用析构函数。因为在C++中初始化和清除工作是强制进行的,用户无权选择避开构造函数和析构函数的调用。

要想在这些特殊的情况下能实现对象的创建和销毁,C++中提供了placement new来应对。在C++中因为可以对运算符进行重载,所以只需对operator new()进行placement重载就能实现在事先分配好的内存空间上调用构造函数来动态创建对象,通过不太常用的对析构函数的显式调用来销毁对象。在这种情况下不涉及内存空间的分配和释放,从而不会导致动态的存储管理,不会对系统的长期稳定运行带来影响。

在C++中placement new运算符是通过对new运算符的重载来实现的,它在嵌入式开发中有着重要的用途。因为我们经常想在内存的某个指定位置上放置一个对象(在嵌入式底层开发中,一个对象可能和一个特定的硬件是直接相关的)。

Placement new的主要用途就是:反复使用一块较大的分配成功的内存来构造不同类型的对象或者它们的数组。比如,可以先申请一个足够大的字符数组,然后当需要时在它上面构造不同类型的对象或其数组。

定位new运算符的基本语法为

char a[100];

X* xp = new(a) X;

其中X是某个事先定义好类,a是一块尺寸大于等于sizeof(X)的内存区域的首地址。由于内存区域是事先已经存在的,placement仅仅只是在相应的内存空间上调用X的构造函数来初始化该片内存区域。

下面的例子显示了如何在一个特定的内存单元里放置一个对象。

#include

using namespace std;

class X {

int i;

public:

X(int ii = 0) : i(ii) {

cout << "this = " << this << endl;

}

~X() {

cout << "X::~X(): " << this << endl;

}

void* operator new(size_t, void* loc) {

return loc;

}

};

int main()

{

int l[10];

cout << "l = " << l << endl;

X* xp = new(l) X(47);

xp->X::~X();

return 0;

}

从中可以看到数组l的地址和构造以及析构函数中输出的this指针的值是相同的。

注意operator new()仅仅返回了传递给它的指针,因此调用者可以决定将对象存放在哪里,这时在该指针所指向的那块内存上,作new表达式一部分的构造函数将被调用。概括来说就是内存空间是事先分配好的,placement new只是在其上调用构造函数来动态创建对象。

然而在销毁对象时则需要格外小心,因为空间不是由new创建的,所以在销毁对象时也应该将对象的析构和内存空间的释放分开来做。我们要销毁对象就需要调用析构函数,但此时不能将内存空间释放掉,因为内存空间不是由new所分配出来的。解决办法是用非常特殊的语法,我们可以显式的调用构造函数。例如:

xp->X::~X();

这样将会只销毁对象而不会释放内存。通过placement new和显式调用析构函数的方式我们就可以在已有的空间上动态地创建和销毁对象。在嵌入式领域,为了稳定性,我们可以在程序一开始时分配好足够的空间,在上面构造和销毁对象,充分享受这种便利性,同时也避免了通常的new和delete所带来的内存碎片问题。

使用placement new构造起来的对象或其数组,要显示地调用它们的析构函数来销毁(析构函数并不释放对象的内存),千万不要使用delete。这是因为,placement new构造起来的对象或其数组的大小并不一定等于原来分配的内存大小,而且空间也不一定是在堆上分配的,使用delete的话将会出现严重的问题。

上一篇:NFC之PN532使用

下一篇:container_of分析

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技集团有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部