多少年了,一直处于C与C++混用的状态,申请空间一直用malloc,释放空间一直用free,为什么?因为他们好理解易操作,就如同输出一直用printf而不用<<,输入一直用scanf而不用>>。如果用new和delete,就会涉及到数组的问题,而我却一直没有好好理解过这种情况。今天突然有兴致深入分析下,于是写了下面一段代码:


代码
#include <iostream>
using namespace std; int g_i = 0; class TestClass
{
public:
    int id;     TestClass()
    {
        id = ++g_i;
        cout << id << " TestClass created." << endl;
    }     ~TestClass()
    {
        cout << id << " TestClass deleted." << endl;
    }
}; int main(int argc, char* argv[])
{
    TestClass * pTestClass = new TestClass;
    delete pTestClass;     return 0;
}

  编译运行之后可以看到:

1 TestClass created.
1 TestClass deleted.

  反汇编之后可以看出,程序首先申请了4字节的空间,然后调用构造方法进行初始化,接着便把地址赋给了pTestClass,最后调用析构方法收尾并把空间释放掉:


代码
push    4
call    operator_new         ...... mov     ecx, [ebp+var_18]
call    TestClass__TestClass
mov     [ebp+var_24], eax         ...... push    1
mov     ecx, [ebp+var_1C]
call    TestClass___scalar_deleting_destructor

  再来看看申请对象数组的情况,将main函数中的代码修改为:

TestClass * pTestClass = new TestClass[4];
delete [] pTestClass;

  编译运行之后可以看到:


1 TestClass created.
2 TestClass created.
3 TestClass created.
4 TestClass created.
4 TestClass deleted.
3 TestClass deleted.
2 TestClass deleted.
1 TestClass deleted.

  反汇编之后可以看出,程序首先申请了20字节空间,然后将数组大小存放到前4个字节,调用构造方法将后面的4个对象指针初始化(4*4+4=20B),接下来才把空间指针赋给pTestClass。在清除空间的时候,程序根据存储在前4个字节中的长度,通过一个循环来从后往前调用每个对象的析构方法,最后才把空间释放掉:


代码
push    14h
call    operator_new         ...... push    offset TestClass___TestClass
push    offset loc_40128F
mov     eax, [ebp+var_18]
mov     dword ptr [eax], 4
push    4
push    4
mov     ecx, [ebp+var_18]
add     ecx, 4
push    ecx
call    vector constructor iterator         ...... push    3
mov     ecx, [ebp+var_1C]
call    TestClass___vector_deleting_destructor

  那么如果将main函数中的代码修改为申请一个对象的数组,情况又如何呢?

TestClass * pTestClass = new TestClass[1];
delete [] pTestClass;

  通过反汇编可以看出,即使是申请一个对象的指针数组,编译器的处理都是一样的,多申请4个字节的空间来保存数组大小。所以,只要在new操作时,使用了[],在delete时也必须使用[],否则,程序将把前面存贮数组大小的4个字节按照对象指针来处理,这样在调用析构方法的时候就会出错。

  那么如果是在一个文件中进行new操作,在另一个文件中delete的时候,如何判断使用delete还是delete []呢?一种方法是用一个变量来保存新申请对象的个数,在delete的时候进行判断,如果个数大于1,使用delete[],否则使用delete;另一种方法是,在申请对象的时候,一律用上[],这样在delete的时候也一律用上[]就没问题。

  最后我们来看看申请简单类型数组的情况,将main函数中代码改为:

int * pInt = new int[4];
delete [] pInt;

  反汇编后可以看到,由于是简单数据类型,不需要调用构造方法和析构方法,在申请空间时,没有多申请4个字节的空间来保存数组大小,所以,调用delete进行删除和调用delete []进行删除是完全一样的。


push    10h
call    operator_new         ...... push    edx
call    free_4062B0

今天才发现,在多线程下new和delete的时候,必须选择上多线程库,不然可能造成进程崩溃,具体设置位置在工程设置“C/C++”选项卡的“Code Generation”下的“Use run-time library”中。

http://www.cnblogs.com/God4/articles/1887184.html#2320993

VC6下深入理解new[]和delete[](在多线程下new和delete的时候,必须选择上多线程库,不然可能造成进程崩溃)的更多相关文章

  1. ASP.NET MVC Filters 4种默认过滤器的使用【附示例】 数据库常见死锁原因及处理 .NET源码中的链表 多线程下C#如何保证线程安全? .net实现支付宝在线支付 彻头彻尾理解单例模式与多线程 App.Config详解及读写操作 判断客户端是iOS还是Android,判断是不是在微信浏览器打开

    ASP.NET MVC Filters 4种默认过滤器的使用[附示例]   过滤器(Filters)的出现使得我们可以在ASP.NET MVC程序里更好的控制浏览器请求过来的URL,不是每个请求都会响 ...

  2. [转帖]/proc/sys/net/ipv4/ 下参数理解

    /proc/sys/net/ipv4/ 下参数理解,方便服务器优化 2017年06月02日 16:52:27 庞叶蒙 阅读数 3065 https://blog.csdn.net/pangyemeng ...

  3. 对于多线程下Servlet以及Session的一些理解

    今天,小伙伴突然问到了Servlet是不是线程安全的问题.脑子当时一卡壳,只想到了单实例多线程.这里做一些总结. Servlet体系是建立在Java多线程的基础之上的,它的生命周期是由Tomcat来维 ...

  4. 定制自己的new和delete:operator new 和 operator delete

    new和delete不同用法 基本用法 int * aptr = new int(10); delete aptr, aptr = nullptr; 上面的代码是我们最基本也是最常见的使用new和de ...

  5. Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask

    CyclicBarrier 接着讲多线程下的其他组件,第一个要讲的就是CyclicBarrier.CyclicBarrier从字面理解是指循环屏障,它可以协同多个线程,让多个线程在这个屏障前等待,直到 ...

  6. Java多线程20:多线程下的其他组件之CountDownLatch、Semaphore、Exchanger

    前言 在多线程环境下,JDK给开发者提供了许多的组件供用户使用(主要在java.util.concurrent下),使得用户不需要再去关心在具体场景下要如何写出同时兼顾线程安全性与高效率的代码.之前讲 ...

  7. Effective C++ 第二版 5)new和delete形式 6) 析构函数里的delete

    内存管理 1)正确得到: 正确调用内存分配和释放程序; 2)有效使用: 写特定版本的内存分配和释放程序; C中用mallco分配的内存没有用free返回, 就会产生内存泄漏, C++中则是new和de ...

  8. 【JAVA】HashMap的原理及多线程下死循环的原因

    再次翻到以前工作中遇到的一个问题,HashMap在多线程下会出现死循环的问题,以前只是知道会死循环,导致CPU100%把机器拖跨,今天来彻底看看 首先来看下,HashMap的原理:HashMap是一个 ...

  9. Linux——多线程下解决生产消费者模型

    我们学习了操作系统,想必对生产消费者问题都不陌生.作为同步互斥问题的一个经典案例,生产消费者模型其实是解决实际问题的基础模型,解决很多的实际问题都会依赖于它.而此模型要解决最大的问题便是同步与互斥.而 ...

随机推荐

  1. [Angular] Bind async requests in your Angular template with the async pipe and the "as" keyword

    Angular allows us to conveniently use the async pipe to automatically register to RxJS observables a ...

  2. [Yarn] Use Yarn to Create an Alternative Import Name of an Installed Library

    In this lesson we'll show how to use yarn to alias the names of same npm libraries but install diffe ...

  3. Hibernate的ID主键生成策略

    ID生成策略(一) 通过XML配置实现ID自己主动生成(測试uuid和native) 之前我们讲了除了通过注解的方式来创建一个持久化bean外.也能够在须要持久化的bean的包路径下创建一个与bean ...

  4. 用JavaScript和CSS实现“在页面中水平和垂直居中”的时钟

    思路:实现起来最麻烦的事实上是水平居中和垂直居中,当中垂直居中是最麻烦的. 考虑到浏览器兼容性,网上看了一些资料,发如今页面中垂直居中确实没有什么太好的办法. 于是就採用了position:fixed ...

  5. poj2151之概率DP

    Check the difficulty of problems Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4403   ...

  6. 用DOM4J包实现对xml文件按属性分离。

    转自本人博客:http://www.xgezhang.com/dom4j_xml_separata.html dom4j是一个Java的XML API.类似于jdom.用来读写XML文件的. dom4 ...

  7. Python 网络爬虫与信息获取(一)—— requests 库的网络爬虫

    1. 安装与测试 进入 cmd(以管理员权限),使用 pip 工具,pip install requests 进行安装: 基本用法: >> import requests >> ...

  8. 【计算机视觉】OpenCV中直方图处理函数简述

    计算直方图calcHist 直方图是对数据集合的统计 ,并将统计结果分布于一系列提前定义的bins中.这里的数据不只指的是灰度值 ,统计数据可能是不论什么能有效描写叙述图像的特征. 如果有一个矩阵包括 ...

  9. js如何实现点击显示和隐藏表格

    js如何实现点击显示和隐藏表格 一.总结 一句话总结: 1.给table或者table里面的元素添加点击事件, 2.然后判断当前表格的数据显示或者隐藏, 3.然后通过display属性显示(非none ...

  10. unresolved external symbol __forceAtlDllManifest错误的解决

    作者:朱金灿 来源:http://blog.csdn.net/clever101 晚上编译一个ATL程序,出现一些诡异的错误: 1>CGreet.obj : error LNK2001: unr ...