添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

在C++中内存分为五个区:堆、栈、自由存储区、全局/静态存储区和常量存储区。

堆区:用户使用new获得的内存在这里。用户需要自行管理其声明周期,也就是说一个new要对应一个delete,如果因为某些原因(之后我会说明一些可能的原因)内存没有被释放,那么在程序结束后,会由操作系统自行回收,这显然不是我们想看到的。

栈区:存储局部变量、函数参数等,比方说你在某个函数里定义了一个int变量a,这个a就存放在栈区。这块内存的生命周期由系统管理,不需要我们去操心。

自由存储区:用malloc分配的内存放置在这里。这块内存和堆很相似,不过是使用free来释放内存的。

全局/静态存储区:存放全局变量和静态变量。

常量存储区:存放常量,不允许更改。

new和delete

void testDelete(){
    int *p = new int;
    cout << *p << endl;
    cout << &p << endl;
    *p=1;
    cout << *p << endl;
    cout << &p << endl;
    delete p;
    cout << *p << endl;
    cout << &p << endl;
    p = nullptr; //程序到此停止执行
    cout << *p << endl;
    cout << &p << endl;

可以看出 delete指针并非将该指针弃置不用,而是将其指向的内存中的数据清除,但是指针仍然指向原来的内存!

如果我们想按照delete的英文本意,把这个指针从世界上彻底销毁,需要将指针的值赋为nullptr

如果可以,我们应该使用STL提供的shared_ptr和unique_ptr替换原始指针,这样我们可以不用自行管理内存的生命周期,获得类似JAVA和C#的自动内存回收体验。

shared_ptr<int> p = make_shared<int>(1);
shared_ptr<int> q(new int(2));
注意:

不要使用相同的内置指针初始化(或reset)多个智能指针。
不delete get()返回的指针
不适用get()初始化或reset另一个智能指针
如果使用了get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了。

不过你使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器。

allocator类

该类帮助我们将内存分配和对象构造分离开来,它分配的内存是原始的、未构造的。

allocator<string> alloc;//可以分配string的allocator对象
auto const p = alloc.allocate(n);//分配n个未初始化的string

malloc/free

从C程序员转换过来的C++程序员总是有个困惑:new/delete到底究竟和C语言里面的malloc/free比起来有什么优势?或者是一样的?

malloc/free只是对内存进行分配和释放;new/delete还负责完成了创建和销毁对象的任务。
new的安全性要高一些,因为他返回的就是一个所创建的对象的指针,对于malloc来说返回的则是void*,还要进行强制类型转换,显然这是一个危险的漏洞。
我们可以对new/delete重载,使内存分配按照我们的意愿进行,这样更具有灵活性,malloc则不行。
不过,new/delete也并不是十分完美,大概最大的缺点就是效率低(针对的是缺省的分配器),原因不只是因为在自由存储区上分配(和栈上对比),而且new只是对于堆分配器(malloc/realloc/free)的一个浅层包装,没有针对小型的内存分配做优化。另外缺省分配器具有通用性,它管理的是一块内存池,这样的管理往往需要消耗一些额外空间。我们可以针对new/delete进行重写以追求更高的效率,对于这方面更深入的探讨可以参考《Effective C++》第八章。

    static void* operator new(size_t sz);
    static void operator delete(void* p);

new 对象实际上做了2件事:调用opeator new,在自由存储区分配一个sizeof(A)大小的内存空间;然后调用构造函数A(),在这块内存空间上类砖砌瓦,建造起我们的对象。

同样对于delete,则做了相反的两件事:调用析构函数~A(),销毁对象,调用operator delete,释放内存。