测试代码:

#include <iostream>

using namespace std;

class AA {
public:
    AA(size_t count = 1)
    {
        _a = new int[count];
        cout<<"AA()"<<endl;
    }
    
    ~AA()
    {
        cout<<"~AA()"<<endl;
        delete[] _a;
        // cout<<"~AA()"<<endl;
    }

private:
    int* _a;
};

int main() {
    char *str = new char[20];
    delete str;
    cout<<"0"<<endl;


    AA* p3 = new AA;         // 不报错,但未清理干净。p3的构造函数开辟的空间没有被释放
    free(p3);
    cout<<"1"<<endl;
    AA* p4 = new AA[10];   // dump
    AA* p5 = &p4[2];
    delete p4;
    cout<<"2"<<endl;
    AA* p5 = new AA;     // dump
    delete[] p5; 
    cout<<"3"<<endl;
}

 

似乎new/delete/delete[]的具体实现是和编译器相关的

new的时候会额外申请4字节或更多字节的空间,存放元素个数,这样delete[]的时候,就知道要析构多少个元素。

https://www.cnblogs.com/wkfvawl/p/10846851.html

有的文档里说delete数组可以成功,但是在运行centos7 g++5.5编译的程序时会直接dump:

*** Error in `./a.out': munmap_chunk(): invalid pointer: 0x0000000001fe7c48 ***

但是对于没有显示析构函数的类或者内置变量,就能正常运行。

new既是关键字也是操作符:

newoperator new之间的联系:
1)new表达式调用一个名为operator new(或者operator new[])的标准库函数。该函数分配一块足够大的、原始的、未命名的内存空间以便存储A类型的对象(或者对象数组);
2)编译器运行相应地构造函数以构造这些对象,并为其传入初始值;
3)对象被分配了空间并构造完成,返回一个指向该对象的指针
事实上,如果类A重载了operator new,那么将调用A::operator new(size_t size),如果没有重载,就调用全局函数::operator new(size_t size),全局new操作符由c++默认提供。

相关知识:

1.如果你希望将对象产生于堆上,请使用new operator2.如果你只打算分配内存,请使用operator new,就不会调用构造函数。
3.如果你打算在堆对象产生时自己决定内存分配方式,请自己重载operator new4.如果你打算在已分配的内存中构造对象,请使用placement new

new和malloc

operator new 从自由存储区上为对象动态分配内存空间,而 malloc 从堆上动态分配内存。
事实上,我在网上看的很多博客,划分自由存储区与堆的分界线就是new/delete与malloc/free。然而,尽管C++标准没有要求,但很多编译器的new/delete都是以malloc/free为基础来实现的。那么请问:借以malloc实现的new,所申请的内存是在堆上还是在自由存储区上?

从技术上来说,堆(heap)是C语言和操作系统的术语。堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free可把内存交还。
而自由存储是C
++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,
这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。
我们所需要记住的就是: 堆是操作系统维护的一块内存,而自由存储是C
++中通过new与delete动态分配和释放对象的抽象概念。堆与自由存储区并不等价。

在使用shared_ptr的时候,默认是不会delete[]数组(c++17开始才能传入数组类型: std::shared_ptr<int[]> p(new int[10]);),需要传入自定义的删除器:

void myDelete (int *p)//自己的删除器,删除整型指针用的,当智能指针引用计数为0
//就会自动调用来删除对象。
{
    cout << "这里被调用了"<<endl;
    delete []p;
}
std::shared_ptr<int> p1(new int[5], deleter);

 

p.s. C++标准规定:delete空指针是合法的,没有副作用。

posted on 2020-12-16 17:27  SimbaStar  阅读(80)  评论(0编辑  收藏  举报