内存陷阱

这里总结的常见内存陷阱有:

  • 数据缓冲区分配不足,导致缓冲区溢出
  • 越界内存访问
  • 内存泄漏
  • 重复 delete 指针

代码如下:

#include <iostream>
#include <cstring>

int main() {
    // 内存陷阱 memory pitfalls
    {
        // 数据缓冲区分配不足,导致缓冲区溢出
        char buffer[1024] {0};
        char* nextChunk {new char[1025]{0}};
        strcat(buffer, nextChunk);  // bug!
    }

    {
        // 越界内存访问
        // 对于函数 fillWithM(),如果参数 text 指向的字符串末尾的'\0'丢失了
        // 则字符串边界之外的内存也会被修改
        auto fillWithM {[](char* text){
            for (int i{0}; text[i] != '\0'; ++i) {
                text[i] = 'm';
            }
        }};

    }

    {
        // 内存泄漏
        // 在函数 doSomething() 中将指针指向了新的地址,而原地址的内存未释放
        // 所以原来的 Simple 对象以及它的成员指针 m_intPtr 指向的 int 值所占的内存就发生了泄漏
        
        class Simple {
        public:
            Simple() {m_intPtr = new int{};}  // !!!
            ~Simple() {delete m_intPtr;}
            void setValue(int value) {*m_intPtr = value;}
        private:
            int* m_intPtr;
        };

        auto doSomething{[](Simple*& outSimplePtr){
            outSimplePtr = new Simple{};  // bug! 原来的对象未 delete
        }};

        Simple* simplePtr {new Simple{}};
        doSomething(simplePtr);  // !!!
        delete simplePtr;  // 只清理了第二个对象(在函数 doSomething() 中 new 的对象)
    }

    {
        // 重复删除 Double-Deletion,悬空指针 Dangling pointer
        int* myInt {new int{5}};
        delete myInt;  // delete,此时 myInt 是悬空指针,即它指向的地址已经不归当前程序管辖了,对当前程序而言这个地址是一个无效的地址
        delete myInt;  // 又一次delete
        // 如果 myInt 指向的内存在第一次 delete 之后被其他程序使用了, 
        // 第二次 delete 就是问题了,程序可能会释放已分配给其他程序的内存。
        // 正确的做法是在 delete 后立即将指针赋值为 nullptr
    }

    return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注