2022-06-25 C++老八股之 new 的内存用 free 回收有危险

C++老八股之 new 的内存用 free 回收有危险


关于 new delete malloc free

C++为什么要用 new 和 delete 。

大概是为了解决某些含有资源,需要确保通过析构,释放资源的类的对象留存。你可以认为是为了保障 RAII 的一种设置。

C则不必为此操心,虽然为此会更操心,但是操心也没卵用,没有class封装,只能整天提心内存泄漏,更没有 RAII 如此优雅的机制。


举个例子

对于内置类型,是 OK 的,对只含有内置类型的类对象,也是 OK 的。

因为其内存和类实体是合一的,实体即内存。

以下代码是不安全的,只供学习!

#include <iostream>
#include <vector>

struct canFree
{
    int intArry[3] = {0, 1, 2};
};

int main()
{
    canFree *testCanFree = new canFree();

    int *rawDataCf = testCanFree->intArry;

    std::cout << "testCanFree before free " << std::endl;

    for (int i = 0; i != 3; ++i)
    {
        std::cout << *(rawDataCf + i) << std::endl;
    }

    free(testCanFree);

    std::cout << "testCanFree after free " << std::endl;

    for (int i = 0; i != 3; ++i)
    {
        std::cout << *(rawDataCf + i) << std::endl;
    }

    return 0;
}

对于非内置类型,包括标准容器,则必然是 LeakMem。

因为类实体和内存是分离的,实体只包含一个符号,符号指向内存,把符号抹除,内存还在。

#include <iostream>
#include <vector>

struct canNotFree
{
    std::vector<std::string> strVec = {"free", "and", "memleak"};
};

int main()
{
    canNotFree *testCanNotFree = new canNotFree();

    std::string *rawDataCnf = testCanNotFree->strVec.data();

    std::cout << "testCanNotFree before free " << std::endl;

    for (int i = 0; i != 3; ++i)
    {
        std::cout << *(rawDataCnf + i) << std::endl;
    }

    free(testCanNotFree);

    std::cout << "testCanNotFree after free " << std::endl;

    for (int i = 0; i != 3; ++i)
    {
        std::cout << *(rawDataCnf + i) << std::endl;
    }

    return 0;
}

相反情况malloc内存delete释放,也有问题。

首先malloc这种有初始值的类就不靠谱,它只分配内存,不初始化,所以对上面的代码,无论是canFree和canNotFree对象都没有初始值。

    canNotFree *cnf = (canNotFree *)malloc(sizeof(std::vector<std::string>));
    
    canFree *cf = (canFree *)malloc(sizeof(int[3]));

当然如果你说可以再给成员赋值,OK,可以。那再问一句,含虚函数的类怎么办,虚函数表指针怎么保证正确?

其次,malloc出的是 void* 纯内存,如果只是赋给 一个 void* 对象,delete 一个 void* 类型指针不合法,直接崩。

    void *test = malloc(sizeof(char) * 8);
    delete test;

当然如果你说可以强制类型转换再delete,OK,你赢了。

    delete static_cast<int64_t *>(test);

最后,谁说malloc只能弄一个对象,完全可以弄一个对象的动态数组,这时delete就不行了吧 ( 这又是另外一个话题,delete动态数组,只调用第一个元素的析构,如果碰到持有资源的对象,就会导致资源泄漏 )。

当然如果你说可以delete[],我对你的敬仰之情如涛涛江水连绵不绝,还等什么,赶紧去祸害大厂去吧。

    int *test = (int *)malloc(16);
    delete[] test;

总结

相信如果运行过上面的代码,就比较容易理解了。

深入理解,可能还是需要自己实现一个符号和资源分离的类,比如 vector 容器,还要理解符号和实体之间的关系。

我写下月亮两个字,你能知道这是天上的阴晴圆缺,我把月亮两个字从笔记上擦掉,你晚上抬头,依旧悲欢离合,没有任何区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不停感叹的老林_<C 语言编程核心突破>

不打赏的人, 看完也学不会.

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值