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;
}