布局new操作符引发的有关析构函数的探索与总结

<布局new操作符——不负责分配内存>

布局new操作符能够使我们在分配内存时指定位置。

如下代码交代了相关语法:

  char *buffer =
new char[BUF];

  JustTesting *p1,
*p2;

   p1 = new
(buffer) JustTesting;  //额外加入的(buffer)用来指定位置

这意味着将JustTesting的一个实例分配在了以buffer为头地址的内存空间中,并用指针p1指向这个实例。

换句话说,我们将JustTesting实例化在了已经被开辟的内存空间buffer中。

  这时候我们不禁要问一句,我们在同一个位置开辟了两次内存空间,这合理吗?

  并且在相关代码即将结束时,我们需用如下代码析构对象并释放内存。

    pc->~JustTesting();

    delete[]buffer;

  对应的,如果析构函数的作用是释放内存空间,我们对同一内存空间释放了两次,这又合理吗?

  一个合理的猜测是内存空间可被重叠分配和释放,只要使用的合理,不存在越界等问题,就是合乎语法的。

  但是问题远没我们猜测的这么复杂。

  首先需要说明的是,布局new操作符是一个不折不扣的骗子。它的责任仅仅在指定的内存空间(buffer)实例化出一个JustTesting的对象而已,并不负责分配内存。也就是说,我们在使用布局new操作符的时候,必须保证指定的地址是安全的。这正是{Char
*buffer = new char[BUF];}这行代码的作用。

<析构函数——不负责回收内存>

  其次,显示调用析构函数并不会起到释放内存的作用,它和普通的函数并无区别,仅仅将其中代码运行一遍而已。

  那为什么还要显示调用它呢?反正真正起到释放内存作用的是delete。释放之后这块内存又会被重新利用并覆盖。

  这一点都没错,但是当构造函数中有new操作符分配的额外内存时情况就不一样了。这将导致内存泄露。所以我们显示调用析构函数正是为了释放在构造函数中额外“借来”的内存。

  结论就是,构造函数和析构函数的调用并没有开辟或回收内存的作用。

<内存由谁分配?>

  那么我们使用如下代码时,确实分配了内存:

    JustTesting one;

  没错,或许你还能这样另一种确实分配了内存的情况:

    *p2 = new JustTesting;

  与之对应的就有:

    delete p2; //我们总是以这种方式去析构指针对象

  这下明白些了,在声明一个对象的时候隐含了new过程。对应地,删除对象的时候(例如超出作用域)也隐含了delete过程。(注意,new和布局new有着本质区别。)

<最后值的注意的一点>

  尽管构造和析构函数可以显示调用,但是当其中包含new和delete时,多次使用是危险的。它们会造成内存泄露和重复释放相同内存区。

布局new操作符引发的有关析构函数的探索与总结

时间: 2024-10-25 00:03:29

布局new操作符引发的有关析构函数的探索与总结的相关文章

由一个bug引发的SQLite缓存一致性探索

问题 我们在生产环境中使用SQLite时中发现建表报“table xxx already exists”错误,但DB文件中并没有该表.后面才发现这个是SQLite在实现过程中的一个bug,而这个bug与数据字典的一致性相关,下面这篇文章主要讨论SQLite的缓存机制,以及缓存一致性实现的策略,希望对大家了解SQLite缓存机制有一定的帮助. 缓存 SQLite中缓存主要包括两方面,数据字典缓存和数据页缓存.SQLite本身是一个文件数据库,所有的数据都在一个DB文件中,文件以块(page)的形式

placement new 操作符

placement new操作符能够在分配内存时指定内存位置.下面的程序使用了placement new操作符和常规new操作符给对象分配内存. // placenew.cpp -- new, placement new, no delete #include <iostream> #include <string> #include <new> using namespace std; const int BUF = 512; class JustTesting {

任务七:实现常见的技术产品官网的页面结构及样式布局

任务目的 通过实现一个常见的技术产品官网,加深对于HTML,CSS的实战能力 学习掌握如何在没有标注的情况下实现设计稿到页面的精确转变 任务描述 通过HTML及CSS实现设计稿 设计稿PSD文件(点击下载),效果如 效果图(点击打开) 设计稿是有一定宽度的,这个宽度为页面的最小宽度,也就是说,当浏览器窗口宽度小于设计稿宽度时,允许出现横向滚动条,页面内容宽度保持不变,但是当浏览器窗口宽度大于设计稿宽度时,页面部分内容的宽度应该保持和浏览器窗口宽度一致,具体哪些部分题目不做具体指明,看看大家的判断

单继承下的虚表布局

在C++中,多态表示 “以一个公有基类的指针或引用,寻址出一个派生类对象” . 假如有调用 ptr->get_c() ,其中ptr是基类指针,get_c()是一个虚函数.要在执行期能正确调用get_c()的实例,我们需要知道: 1.ptr所指对象的真正类型,以便我们选择正确的get_c()实例. 2.get_c()实例的位置,以便我们能够调用他. 在实现上,编译时期会构建出来一张虚表,表格中有程序的虚函数的执行期地址. 为了找到这个表格,每一个类对象被安插一个由编译器产生的指针,指向虚表. 为了

asp.net面试题汇总

1.静态成员和非静态成员的区别? 答: 静态变量使用 static 修饰符进行声明,在类被实例化时创建,通过类进行访问不带有 static 修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对象进行访问一个类的所有实例的同一静态变量都是同一个值,同一个类的不同实例的同一非静态变量可以是不同的值静态函数的实现里不能使用非静态成员,如非静态变量.非静态函数等 示例: using System; using System.Collections.Generic; using System.Te

《C++ Primer Plus》学习笔记7

<C++ Primer Plus>学习笔记7 第12章 类和动态内存分配 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

FaceBook推出的Android图片载入库-Fresco

欢迎关注ndroid-tech-frontier开源项目,定期翻译国外Android优质的技术.开源库.软件架构设计.測试等文章 原文链接:Introducing Fresco: A new image library for Android 译者 : ZhaoKaiQiang 校对者: Chaossss 校对者: bboyfeiyu 校对者: BillionWang 状态 : 完毕 在Android设备上面,高速高效的显示图片是极为重要的. 过去的几年里,我们在怎样高效的存储图像这方面遇到了很

C++ stringstream介绍,使用方法与例子

From: http://www.usidcbbs.com/read-htm-tid-1898.html C++引入了ostringstream.istringstream.stringstream这三个类,要使用他们创建对象就必须包含sstream.h头文件. istringstream类用于执行C++风格的串流的输入操作. ostringstream类用于执行C风格的串流的输出操作. strstream类同时可以支持C风格的串流的输入输出操作. istringstream类是从istream

【Android开发经验】FaceBook推出的Android图片加载库-Fresco

欢迎关注ndroid-tech-frontier开源项目,定期翻译国外Android优质的技术.开源库.软件架构设计.测试等文章 原文链接:Introducing Fresco: A new image library for Android 译者 : ZhaoKaiQiang 校对者: Chaossss 校对者: bboyfeiyu 校对者: BillionWang 状态 : 完成 在Android设备上面,快速高效的显示图片是极为重要的.过去的几年里,我们在如何高效的存储图像这方面遇到了很多