• 【C++】《Effective C++》第八章


    第八章 定制new和delete

    对于程序开发来说,了解C++内存管理例程的行为是非常重要的。其中两个主角是分配例程和归还例程(operator newoperator delete),配角是new-handker,这是当operator new无法满足客户的内存需求时所调用的函数。

    注意STL容器所使用的heap内存是由容器所拥有的分配器对象(allocator objects)管理,不是被newdelete直接管理。

    条款49:了解new-hander的行为

    请记住

    • set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用。
    • Nothrow new是一个颇为局限的工具,因为它只适用于内存分配;后继的构造函数调用还是可能抛出异常。

    条款50:了解newdelete的合理替换机制

    一般处于下列原因可能想要替换编译器提供的operator newoperator delete

    • 为了检测运用错误。
    • 为了收集动态分配内存的使用统计信息。
    • 为了增加分配和归还的速度。
    • 为了降低缺省内存管理器带来的空间额外开销。
    • 为了弥补缺省分配器中的非最佳齐位。
    • 为了将相关对象成簇集中。
    • 为了获得非传统的行为。

    下面是一个”为了检测运用错误“而实现的简单的 operator new 的例子,通过在首部和尾部插入一个签名,返回中间内存块给程序使用,如果程序在使用内存时发生过在区块前或区块后写入的行为,那么签名就会被修改,因此可以检测这种行为:

    static const int signature = 0xDEADBEEF; // 边界符
    typedef unsigned char Byte;
    void* operator new(std::size_t size) throw(std::bad_alloc) {
        // 多申请一些内存来存放占位符
        size_t realSize = size + 2 * sizeof(int);
        // 申请内存
        void *pMem = malloc(realSize);
        if (!pMem) throw bad_alloc();
        // 写入边界符
        *(reinterpret_cast<int*>(static_cast<Byte*>(pMem)+realSize-sizeof(int)))= *(static_cast<int*>(pMem)) = signature;
        // 返回真正的内存区域
        return static_cast<Byte*>(pMem) + sizeof(int);
    }
    
    

    这个例子主要是展示,它存在很多错误:

    • 所有的 operator new 都应该内含一个循环,反复调用某个 new-handling 函数,这里却没有。
    • C++要求所有 operator new 返回的指针都有适当的对齐。这里 malloc 返回的指针是满足要求的,但是因为上述实现并不是直接返回 malloc 的结果,而是返回一个 int 偏移后的地址,因此无法保证它的安全。

    请记住

    • 有许多理由需要自定的newdelete,包括改善效能、对heap运用错误进行调试、手机heap使用信息。

    条款51:编写newdelete时需固守常规

    请记住

    • operator new应该包含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存要求,就该调用new-handler。它也应该有能力处理0bytes申请。Class专属版本则还应该处理"比正确大小更大的(错误)申请"。
    • operator delete应该在收到null指针时不做任何事。Class专属版本则还应该处理"比正确大小更大的(错误)申请"。

    条款52:写了placement new也要写placement delete

    请记住

    • 当你写一个placement operator new,请确定也写出类对应的placement operator delete。如果没有这样做,你的程序可能会发生隐蔽而时断时续的内存泄漏。
    • 当你声明placement newplacement delete,请确定不要无意识(非故意)地遮掩了它们的正常版本。
  • 相关阅读:
    iOS_文件上传进度条的实现思路-AFNettworking
    快手为什么成功
    Swift 3.1 的一些新特性
    字典类型的字符串转成字典
    phpmyadmin通过日志文件拿webshell
    计算机网络基础知识
    写一个php小脚本辅助渗透测试
    Zabbix exp编写
    sqlmap里如何添加字典
    过狗注入学习姿势分享2[投稿华盟网]
  • 原文地址:https://www.cnblogs.com/parzulpan/p/13542056.html
Copyright © 2020-2023  润新知