Effective C++ 规则50:了解 new 和 delete 的合理替换时机

1、背景

在 C++ 中,new 和 delete 是动态分配内存的核心操作符。然而,直接使用它们有时会增加程序的复杂性,甚至导致内存泄漏和其他问题。因此,了解何时替换 new 和 delete 并选择更适合的内存管理策略,是编写高效、健壮 C++ 程序的关键。直接使用 new 和 delete 存在以下潜在问题:

  • 内存泄漏: 如果忘记调用 delete 释放内存,就会导致内存泄漏。
  • 异常安全性: 在异常发生时,可能导致内存无法正确释放。
  • 复杂性: 手动管理内存使代码变得更难维护和阅读。
  • 性能问题: 默认的全局 new 和 delete 可能不适合特定场景,例如需要高效的内存池。
  • 无法跟踪分配: 默认 new 和 delete 无法提供关于内存分配的额外信息(如分配大小或位置)。

2、替换 new 和 delete 的常用方法

2.1 、使用智能指针代替原始指针

现代 C++ 提供了智能指针(std::unique_ptr 和 std::shared_ptr),它们能够自动管理内存,避免手动调用 delete。

cpp 复制代码
#include <memory>
#include <iostream>

class Widget {
public:
    Widget() { std::cout << "Widget constructed" << std::endl; }
    ~Widget() { std::cout << "Widget destroyed" << std::endl; }
};

int main() {
    std::unique_ptr<Widget> w = std::make_unique<Widget>();
    // 无需手动调用 delete
    return 0;
}

这样做可以避免内存泄漏,提供异常安全性

2.2、定制全局 new 和 delete

在某些场景中,需要替换全局 new 和 delete 以提供自定义的内存分配行为。

cpp 复制代码
#include <cstdlib>
#include <iostream>

void* operator new(size_t size) {
    std::cout << "Custom new: Allocating " << size << " bytes" << std::endl;
    return std::malloc(size);
}

void operator delete(void* ptr) noexcept {
    std::cout << "Custom delete: Freeing memory" << std::endl;
    std::free(ptr);
}

int main() {
    int* p = new int;
    delete p;
    return 0;
}
  • 优点,可以跟踪内存分配和释放,可优化内存分配以满足特定需求。

2.3、为特定类重载 new 和 delete

对于某些类,可以提供自定义的 new 和 delete,以优化其内存管理。

cpp 复制代码
#include <iostream>
#include <cstdlib>

class Widget {
public:
    static void* operator new(size_t size) {
        std::cout << "Widget custom new: Allocating " << size << " bytes" << std::endl;
        return std::malloc(size);
    }

    static void operator delete(void* ptr) noexcept {
        std::cout << "Widget custom delete: Freeing memory" << std::endl;
        std::free(ptr);
    }
};

int main() {
    Widget* w = new Widget;
    delete w;
    return 0;
}
  • 优点,针对特定类优化内存分配,可实现类级别的内存跟踪和调试。

2.4、使用内存池

在需要频繁分配和释放小对象的场景下,使用内存池可以显著提升性能。

cpp 复制代码
#include <vector>
#include <iostream>

class MemoryPool {
public:
    MemoryPool(size_t objectSize, size_t poolSize)
        : m_objectSize(objectSize), m_poolSize(poolSize) {
        m_pool.reserve(m_poolSize);
        for (size_t i = 0; i < m_poolSize; ++i) {
            m_pool.push_back(std::malloc(m_objectSize));
        }
    }

    ~MemoryPool() {
        for (void* ptr : m_pool) {
            std::free(ptr);
        }
    }

    void* allocate() {
        if (m_pool.empty()) {
            return std::malloc(m_objectSize);
        } else {
            void* ptr = m_pool.back();
            m_pool.pop_back();
            return ptr;
        }
    }

    void deallocate(void* ptr) {
        m_pool.push_back(ptr);
    }

private:
    size_t m_objectSize;
    size_t m_poolSize;
    std::vector<void*> m_pool;
};

int main() {
    MemoryPool pool(sizeof(int), 10);
    int* p = static_cast<int*>(pool.allocate());
    pool.deallocate(p);
    return 0;
}
  • 优点,显著降低小对象的分配和释放开销,避免频繁调用全局的 new 和 delete
相关推荐
tan180°3 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
彭祥.4 小时前
Jetson边缘计算主板:Ubuntu 环境配置 CUDA 与 cudNN 推理环境 + OpenCV 与 C++ 进行目标分类
c++·opencv·分类
lzb_kkk4 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
胖大和尚6 小时前
clang 编译器怎么查看在编译过程中做了哪些优化
c++·clang
钱彬 (Qian Bin)7 小时前
一文掌握Qt Quick数字图像处理项目开发(基于Qt 6.9 C++和QML,代码开源)
c++·开源·qml·qt quick·qt6.9·数字图像处理项目·美观界面
双叶8368 小时前
(C++)学生管理系统(正式版)(map数组的应用)(string应用)(引用)(文件储存的应用)(C++教学)(C++项目)
c语言·开发语言·数据结构·c++
源代码•宸8 小时前
C++高频知识点(二)
开发语言·c++·经验分享
jyan_敬言9 小时前
【C++】string类(二)相关接口介绍及其使用
android·开发语言·c++·青少年编程·visual studio
liulilittle10 小时前
SNIProxy 轻量级匿名CDN代理架构与实现
开发语言·网络·c++·网关·架构·cdn·通信
tan77º10 小时前
【Linux网络编程】Socket - UDP
linux·服务器·网络·c++·udp