美文网首页
C++ 直接内存管理 new / delete 注意事项

C++ 直接内存管理 new / delete 注意事项

作者: 从不中二的忧伤 | 来源:发表于2020-07-20 00:04 被阅读0次

C++ 编译的程序占用内存:

  • 栈区:执行函数时,函数内局部变量的存储单元在栈上创建,变量的声明周期结束后,这些内存单元会自动被释放。栈内存分配运算内置于处理器的指令集,效率高,但是分配的内存有限。
  • 堆区:动态内存分配,程序在运行时使用 malloc 或者 new 申请任意大小内存,由程序员负责在何时使用 free 或者 delete 释放内存。动态内存的生命周期由程序员决定,使用灵活,但是如果在堆上分配了空间,就有责任去回收它,否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间会产生内存碎片。
  • 静态存储区:内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量、static 变量 就在静态存储区分配内存。
  • 常量区:存放常量字符串,程序结束后由系统释放。
  • 代码区:存放函数体(类成员将函数和全局区)的二进制代码

使用 new / delete 直接管理内存:
new : 为对象分配空间并返回一个指向该对象的指针
delete:接受一个动态对象的指针,销毁该对象,并释放与之关联的内存

注意事项:
1、new / delete 需要搭配使用,用 new 申请了一块内存,就必须用 delete 释放该内存。否则会产生内存泄漏。

int main()
{
    int* pi = new int(5);   // 用 new 申请内存 
    delete pi;              // delete 释放该内存 
    
    return 0;
}

2、尽量使用 “值初始化” : 用 () 来初始化

int main()
{
    int* pi = new int;      // 返回一个 int型随机值 
    
    int* pi2 = new int();   // pi2 的值初始化为 0
    
    int* pi3 = new int(10); // pi3 的值初始化为 10 
    
    return 0; 
}

3、指针 delete 后内存被释放,内存中的数据被销毁,此内存不该再被访问。但是 delete 后的指针仍然保留着已经释放的动态内存的地址。建议指针 delete 后,赋值为 nullptr。

int main()
{
    int* pi = new int(123);
    cout << *pi << "\t" << pi << endl;
    
    delete pi;  // 内存被释放,内存中数据被销毁,但是 pi 仍存着这块内存的地址 
    cout << *pi << "\t" << pi << endl;
    
    pi = nullptr;   // 指针地址指空,后续则不能再通过 pi 访问到之前分配的内存 
    cout << *pi << "\t" << pi << endl;
    
    return 0;
}

4、指针指向 nullptr 后,再去 delete 不会调用到析构函数。因为此时 指针不再指向分配的内存的地址,通过此指针系统不知道应该回收哪块内存。所以应该先 delete 指针,再去将指针置空。

class A
{
public:
    A()
    {
        cout << "A()" << endl;
    }
    
    ~A()
    {
        cout << "~A()" << endl;
    }
};

int main()
{
    A* pa1 = new A();   
    pa1 = nullptr;
    delete pa1; // 不会调用析构函数,但是应该回收的内存未被回收 
    
    A* pa2 = new A();
    delete pa2;
    delete pa2; // 会多次调用析构函数,可能产生异常 
    
    A* pa3 = new A();
    delete pa3;
    pa3 = nullptr;  // 内存已被回收,后续再通过 pa3 访问不到原内存 
    
    return 0;
}

5、只有通过 new 出来的地址,才需要 delete 释放对应的内存。对栈上分配的对象取到的地址,不能通过 delete 释放该内存。

int main() 
{
    int i = 10;
    int* pi = &i;
    
    delete pi;  // 错误,pi 指向的是对象 i 在栈上分配的内存对应的地址,不可通过 delete 释放。 
    
    return 0; 
}

6、同一块内存,不能多次释放

int main()
{
    int* p1 = new int(123);
    int* p2 = p1;   // p2指向和 p1 同一块内存 
    
    delete p1;
    delete p2;      // 错误,p2 指向的内存已经在 delete p1 时被释放。 
    
    return 0;
}

7、用 auto 来 new 一个对象时,若传入的是指针,则返回指针的指针 (诡异的写法,尽量避免)

int main()
{
    int* p = new int(123);
    cout << p << endl; 
    cout << *p << endl;
    
    auto pp = new auto(p);  // pp 为 int** 型指针 
    
//  相当于 
//  int** pp = new int*(p) ;

    cout << pp << endl;
    cout << *pp << endl;
    cout << **pp << endl;

    return 0;
}

相关文章

网友评论

      本文标题:C++ 直接内存管理 new / delete 注意事项

      本文链接:https://www.haomeiwen.com/subject/qgddkktx.html