C/C++的常见内存问题

1 内存泄漏:动态分配的内存没有被正确释放,导致程序持续占用内存直至结束运行。
Example:
 

void memoryLeakExample() {
    int* ptr = new int(5); // 分配了一个int类型的内存
    // 这里没有调用delete来释放内存
}

solution:
    自己delete或者使用智能指针


智能指针内存泄露的情况:
假设我们有两个类A和B,它们相互引用对方的实例,使用std::shared_ptr进行管理。这种情况下,如果不加以处理,就会导致循环引用和内存泄漏。

#include <memory>

class B; // 前置声明

class A {
public:
    std::shared_ptr<B> bPtr;
    // ...
};

class B {
public:
    std::shared_ptr<A> aPtr;
    // ...
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();

    a->bPtr = b;
    b->aPtr = a;

    // 此时a和b相互引用,会导致循环引用和内存泄漏

    return 0;
}

solution:
为了解决这个问题,我们可以使用std::weak_ptr来打破循环引用:

#include <memory>

class B; // 前置声明

class A {
public:
    std::shared_ptr<B> bPtr;
    // ...
};

class B {
public:
    std::weak_ptr<A> aWeakPtr; // 使用weak_ptr来打破循环引用
    // ...
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();

    a->bPtr = b;
    b->aWeakPtr = a; // 使用weak_ptr

    // 现在循环引用被打破,不会导致内存泄漏

    return 0;
}

通过将B类中的aPtr改为std::weak_ptr,我们成功打破了循环引用,避免了内存泄漏问题


2 二次释放:尝试释放已经被释放的内存,可能导致程序崩溃。
Example:

int main() {
    int* ptr = new int(5); // 分配了一个int类型的内存
    delete ptr; // 释放内存

    delete ptr; // 尝试再次释放同一块内存,这是错误的

    return 0;
}


solution:
   我们需要确保在释放内存后将指针置为nullptr,这样可以避免尝试释放已经被释放的内存。另外,使用智能指针(如std::unique_ptr)


3 悬空指针:指针指向的内存已经被释放,将指针置为nullptr,导致潜在的错误访问。

int* ptr = new int(5); // 分配了一个int类型的内存
delete ptr; // 释放内存
ptr = nullptr; // 将指针置为空指针
// 在之后的代码中,错误地使用了已经被释放的指针
int value = *ptr; // 这里访问了一个已经被释放的内存

solution:

    多做if  (ptr != nullptr)判断


4 内存越界访问:访问超出动态分配内存范围的内存,可能导致未定义行为。

int* arr = new int[5]; // 分配了包含5个int的内存块

// 尝试访问超出分配内存范围的内存
arr[5] = 10; // 这里访问了arr数组中超出范围的内存

delete[] arr; // 释放内存

solution:
我们需要确保在访问动态分配的内存时不要超出其范围。另外,可以使用标准库提供的容器类(
如std::vector)来代替手动管理动态数组,这样可以避免手动管理内存时可能出现的问题。


5 不正确的所有权管理:多个指针指向同一块动态分配的内存,但没有正确管理所有权,可能导致资源释放错误或重复释放。

int* ptr1 = new int(5); // 分配了一个int类型的内存
int* ptr2 = ptr1; // ptr2指向了ptr1所指向的内存

delete ptr1; // 释放内存

// 错误地尝试使用已经被释放的内存
*ptr2 = 10; // 这里访问了已经被释放的内存

solution:
 使用智能指针或者使用std::move转移所有权

6 竞争条件:多个线程同时访问和修改动态分配的内存,可能导致数据不一致或者意外的行为。

#include <iostream>
#include <thread>

int x = 0;

void incrementX() {
    for (int i = 0; i < 1000000; ++i) {
        x++; // 读取x的值,加一,然后写回x
    }
}

int main() {
    std::thread t1(incrementX);
    std::thread t2(incrementX);

    t1.join();
    t2.join();

    std::cout << "The value of x is: " << x << std::endl;

    return 0;
}

solution:
 使用锁啊std::mutex
 

7 内存破坏:多个线程同时访问和修改同一块内存,可能导致内存破坏和数据损坏。
 

#include <iostream>

int main() {
    int* ptr = new int(5); // 分配了一个int类型的内存

    int* invalidPtr = ptr + 1; // 错误地访问了ptr指针之后的内存

    *invalidPtr = 10; // 错误地修改了无效指针指向的内存

    delete ptr; // 释放内存

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值