`
izuoyan
  • 浏览: 8965217 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

c++中new和delete,delete[]的匹配问题(原创)

阅读更多

这是我在网上逛的时候发现的一个讨论, 起源是<<c>&gt;一书中的一些例子。查了一些资料,把我的结论写在这里。先让我们看一个论述比较好的帖子,e文的,耐心点看。</c>

Mismatching scalar and vector new and delete

In a previous entry I alluded to the problems that can occur if you mismatch scalar "new" with vector <nobr>"delete[]"</nobr> or vice versa.

There is a nice description of C++ memory management in C++ Gotchas: Avoiding Common Problems in Coding and Design on www.informit.com, and I encourage you to read at least the section titled Failure to Distinguish Scalar and Array Allocation before continuing with this entry, because I'm going to use that information as a starting point.

Here's how the Microsoft C++ compiler manages vector allocation. Note that this is internal implementation detail, so it's subject to change at any time, but knowing this may give a better insight into why mixing scalar and vector new/delete is a bad thing.

The important thing to note is that when you do a scalar "delete p", you are telling the compiler, "p points to a single object." The compiler will call the destructor once, namely for the object you are destructing.

When you do <nobr>"delete[] p"</nobr>, you are saying, "p points to a bunch of objects, but I'm not telling you how many." In this case, the compiler needs to generate extra code to keep track of how many it needs to destruct. This extra information is kept in a "secret place" when the vector is allocated with <nobr>"new[]"</nobr>.

Let's watch this in action:

class MyClass { public: MyClass(); // constructor ~MyClass(); // destructor int i; }; MyClass *allocate_stuff(int howmany) { return new MyClass[howmany]; } 

The generated code for the "allocate_stuff" function looks like this:

 push esi mov esi, [esp+8] ;
 howmany ; 
 eax = howmany * sizeof(MyClass) + sizeof(size_t) 
 lea eax, [esi*4+4] 
 push eax 
 call operator new test eax, 
 eax pop ecx je fail push edi 
 push OFFSET MyClass::MyClass 
 push esi lea edi, [eax+4] ; 
 edi = eax + sizeof(size_t) push 4 ; 
 sizeof(MyClass) push edi mov [eax], esi ; 
 howmany call `vector constructor iterator' mov eax, 
 edi pop edi jmp done fail: xor eax, eax done: pop esi retd 4 

Translated back into pseudo-C++, the code looks like this:

MyClass* allocate_stuff(int howmany) 
{
 void *p = operator new( howmany * sizeof(MyClass) + sizeof(size_t)); 
 if (p) 
 {size_t* a = reinterpret_cast<size_t>(p); </size_t>
 *a++ = howmany; vector constructor iterator(a, sizeof(MyClass), &MyClass::MyClass); 
 return reinterpret_cast<myclass>(a); </myclass>
 } 
 return NULL; 
} 

In other words, the memory layout of the vector of MyClass objects looks like this:

howmany
MyClass[0]
MyClass[1]
...
MyClass[howmany-1]

The pointer returned by the <nobr>new[]</nobr> operator is not the start of the allocated memory but rather points to MyClass[0]. The count of elements is hidden in front of the vector.

The deletion of a vector performs this operation in reverse:

void free_stuff(MyClass* p) { delete[] p; } 

generates

 mov ecx, [esp+4] ; 
 p test ecx, 
 ecx je skip push 3 
 call MyClass::`vector deleting destructor` skip ret 4 

Translated back into pseudo-C++, the code looks like this:

void free_stuff(MyClass* p) 
 { if (p) 
 p->vector 
 deleting destructor(3); 
 } 

The vector deleting destructor goes like this (pseudo-code):

void MyClass::vector deleting destructor(int flags) 
{ if (flags & 2) 
 { // if vector destruct 
 size_t* a = reinterpret_cast<size_t>(this) - 1; </size_t>
 size_t howmany = *a; 
 vector destructor iterator(p, sizeof(MyClass), howmany, 
 MyClass::~MyClass); 
 if (flags & 1) 
 { // if delete too operator 
 delete(a); } 
} else { // else scalar destruct 
 this->~MyClass(); // destruct one 
if (flags & 1) 
 { // if delete too operator 
 delete(this); } 
 } 
} 

The vector deleting destructor takes some flags. If 2 is set, then a vector is being destructed; otherwise a single object is being destructed. If 1 is set, then the memory is also freed.

In our case, the flags parameter is 3, so we will perform a vector destruct followed by a delete. Observe that this code sucks the original "howmany" value out of its secret hiding place and asks the vector destructor iterator to run the destructor that many times before freeing the memory.

So now, armed with this information, you should be able to describe what happens if you allocate memory with scalar "new" and free it with vector <nobr>"delete[]"</nobr> or vice versa. Answers to come tomorrow.

Bonus exercise: What optimizations can be performed if the destructor MyClass::~MyClass() is removed from the class definition?

看完之后,两点感触,1.自己学的太肤浅了。2.看东西还是e文好。

我觉得这个帖子里可以得出这样一个结论:当delete只有一个元素的数组时delete和delete[]是没有区别的,当delete一个包含多个元素的数组时,必须采用delete[]。而delete只对堆内存有作用,delete一个变量是不起作用的,变量的内存并没有释放,值也依然存在。同时delete [] NULL和delete NULL是安全的,但是同一个非NULL地址delete两次是致命的。

在delete一个二维数组时,应该:

for(int i=0; i<10; i++)

delete p[i];

delete [] p;

不知小弟理解的对不对,望各位大虾指正。

分享到:
评论

相关推荐

    C++编程思想习题

    12.5.2为一个类重载new和delete 12.5.3为数组重载new和delete 12.5.4构造函数调用 12.5.5对象放置 12.6小结 12.7练习 第13章 继承和组合 13.1组合语法 13.2继承语法 13.3构造函数的初始化表达式表 13.3.1成员对象...

    C++ Primer第四版【中文高清扫描版】.pdf

    5.11 new和delete表达式 150 5.12 类型转换 154 5.12.1 何时发生隐式类型转换 154 5.12.2 算术转换 155 5.12.3 其他隐式转换 156 5.12.4 显式转换 158 5.12.5 何时需要强制类型转换 158 5.12.6 命名的强制类型转换 ...

    C++中避免内存泄露常见的解决方式

     new/delete, array new/arrray delete匹配  case 1:  在类的构造函数与析构函数中没有匹配地调用 new/delete!  解决方法:检查构造函数,在出现new的情况下,按相反的顺序在析构函数中匹配加入delete! ...

    新手学习C++入门资料

    C++中new和delete是对内存分配的运算符,取代了C中的malloc和free。 标准C++中的字符串类取代了C标准C函数库头文件中的字符数组处理函数。 C++中用来做控制态输入输出的iostream类库替代了标准C中的stdio函数库。...

    几个内存泄漏的例子

    几个内存泄漏的例子  new和delete要成对使用...经常看到一些C++方面的书籍中这样提及到内存泄漏问题,这样的说法的意思是比较明白,但对于初学C++程序员还是很难掌握,所以下面举几个反面的例子,希望对大家有帮助。

    非常经典的c++ primer视频教程6-10

    5.11 new和delete表达式 5.12 类型转换 5.12.1 何时发生隐式类型转换 5.12.2 算术转换 5.12.3 其他隐式转换 5.12.4 显式转换 5.12.5 何时需要强制类型转换 5.12.6 命名的强制类型转换 5.12.7 旧式强制类型...

    数据结构C++描述

    数据结构C++描述 目 录 译者序 前言 第一部分 预备知识 第1章 C++程序设计 1 1.1 引言 1 1.2 函数与参数 2 1.2.1 传值参数 2 1.2.2 模板函数 3 1.2.3 引用参数 3 1.2.4 常量引用参数 4 1.2.5 返回值 4 1.2.6 递归...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar

    *7.1.7 动态分配和撤销内存的运算符new和delete 7.2 共用体 7.2.1 共用体的概念 7.2.2 对共用体变量的访问方式 7.2.3 共用体类型数据的特点 7.3 校举类型 7.4 用typedef声明类型 习题 第3篇 基于对象的程序设计 第...

    C++复习资料之系列

    在一个C++程序中,main函数的位置( c )。 (a) 必须在程序的开头 (b) 必须在程序的后面 ( c ) 可以在程序的任何地方 (d) 必须在其它函数中间 2.用C++语言编制的源程序要变为目标程序必须要经过( d )。 (a) ...

    数据结构、算法与应用:C++语言描述(原书第2版)第二部分

    14.6.2 箱子装载问题的最优匹配法 14.6.3 交叉分布 第15章 平衡搜索树 15.1 AVL树 15.1.1 定义 15.1.2 AVL树的高度 15.1.3 AVL树的描述 15.1.4 AVL搜索树的搜索 15.1.5 AVL搜索树的插入 15.1.6 AVL搜索树的删除 15.2...

    数据结构算法与应用(C++语言描述).rar

    1.3.1 操作符new 9 1.3.2 一维数组 9 1.3.3 异常处理 10 1.3.4 操作符delete 10 1.3.5 二维数组 10 1.4 类 13 1.4.1 类Currency 13 1.4.2 使用不同的描述方法 18 1.4.3 操作符重载 20 1.4.4 引发异常 22 1.4.5 友元...

    C++语言描述(PDF合集)

    1.3.1 操作符new 9 1.3.2 一维数组 9 1.3.3 异常处理 10 1.3.4 操作符delete 10 1.3.5 二维数组 10 1.4 类 13 1.4.1 类Currency 13 1.4.2 使用不同的描述方法 18 1.4.3 操作符重载 20 1.4.4 引发异常 22 1.4.5 友元...

    C++智能指针详解.pdf

    你可能会想,如 此多的智能指针就为了解决new、delete匹配问题,真的有必要吗?看完这篇⽂章后,我想你⼼⾥⾃然会有答案。 下⾯就按照顺序讲解如上 7 种智能指针(smart_ptr)。 ⼆、具体使⽤ 1、总括 对于编译器来...

    数据结构与算法:C++描述

    本书在简要回顾了基本的C++ 程序设计概念的基础上,全面系统地介绍了队列、堆栈、树、图等基本数据结构,以及贪婪算法、分而治之算法、分枝定界算法等多种算法设计方法,为数据结构与算法的继续学习和研究奠定了一...

    C++ Primer中文版(第5版)李普曼 等著 pdf 1/3

    Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数程序员学会了C++。 对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使本书成为C++...

    C++Primer视频(初级)下载地址

    第5章new和delete表达式 45.第5章显式转换 46.第6章简单语句 47.第6章if语句 48.第6章switch语句 49.第6章while语 50.第6章for语句 51.第6章dowhile语句 52.第6章break,continue,goto语句 53.第6...

    valgrind 介绍

    valgrind是一款运行在linux下的,用来定位c/c++程序中内存使用方面的错误的工具,包括:内存泄漏、使用未初始化的内存、读/写已释放的内存、读/写内存越界、使用malloc/new/new[]和free/delete/delete[]不匹配,等等...

    C++Primer(第5版 )中文版(美)李普曼等著.part2.rar

    Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数程序员学会了C++。 对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使本书成为C++...

    從新手到高手C++全方位學習

    為了使讀者能夠活學活用,《從新手到高手C++全方位學習》針對重要的概念精心設計了438個實用範例,囊括大量經驗和技巧,即使已從事C++工作多年的朋友,也能從中汲取新的養料。 《從新手到高手C++全方位學習》適合於...

Global site tag (gtag.js) - Google Analytics