在 C++ 里,内存主要分为以下几个区域:
#include
void func() {
int a = 10; // 变量 a 存储在栈上
std::cout << a << std::endl;
}
int main() {
func();
return 0;
}
new
和 delete
(或 malloc
和 free
)进行内存的分配和释放。堆的空间较大,但分配和释放的速度相对较慢,且容易出现内存泄漏问题。例如:#include
int main() {
int* ptr = new int(10); // 在堆上分配内存
std::cout << *ptr << std::endl;
delete ptr; // 释放堆上的内存
return 0;
}
#include
int globalVar = 20; // 全局变量,存储在全局/静态区
void func() {
static int staticVar = 30; // 静态变量,存储在全局/静态区
std::cout << staticVar << std::endl;
}
int main() {
func();
return 0;
}
#include
int main() {
const char* str = "Hello"; // 字符串常量存储在常量区
std::cout << str << std::endl;
return 0;
}
new
和 delete
与 malloc
和 free
的区别new
和 delete
是 C++ 的运算符,具有类型安全性,会自动计算所需内存的大小,并返回正确类型的指针。而 malloc
和 free
是 C 语言的函数,返回 void*
类型的指针,需要手动进行类型转换。例如:#include
int main() {
int* ptr1 = new int(10); // new 自动处理类型
int* ptr2 = (int*)malloc(sizeof(int)); // malloc 需要手动类型转换
delete ptr1;
free(ptr2);
return 0;
}
new
在分配内存后会调用对象的构造函数进行初始化,delete
在释放内存前会调用对象的析构函数进行资源清理。而 malloc
和 free
只是单纯地分配和释放内存,不会调用构造和析构函数。例如:#include
class MyClass {
public:
MyClass() { std::cout << "Constructor" << std::endl; }
~MyClass() { std::cout << "Destructor" << std::endl; }
};
int main() {
MyClass* obj1 = new MyClass(); // 调用构造函数
delete obj1; // 调用析构函数
MyClass* obj2 = (MyClass*)malloc(sizeof(MyClass)); // 不调用构造函数
free(obj2); // 不调用析构函数
return 0;
}
new
在内存分配失败时会抛出 std::bad_alloc
异常,而 malloc
在内存分配失败时返回 NULL
指针。内存泄漏指的是程序在动态分配内存后,由于某种原因未能正确释放这些内存,导致这部分内存无法被再次使用。常见的原因包括忘记调用 delete
或 free
,或者在异常处理中没有正确释放内存。例如:
#include
void memoryLeak() {
int* ptr = new int(10);
// 忘记释放内存
// delete ptr;
}
int main() {
memoryLeak();
return 0;
}
为避免内存泄漏,可以使用智能指针(如 std::unique_ptr
、std::shared_ptr
和 std::weak_ptr
),它们会自动管理内存的生命周期。例如:
#include
#include
void noMemoryLeak() {
std::unique_ptr ptr = std::make_unique(10);
// 不需要手动释放内存,ptr 离开作用域时会自动释放
}
int main() {
noMemoryLeak();
return 0;
}
悬空指针是指指向已经被释放的内存的指针。使用悬空指针会导致未定义行为。例如:
#include
int main() {
int* ptr = new int(10);
delete ptr;
// ptr 现在是悬空指针
// *ptr = 20; // 未定义行为
return 0;
}
为避免悬空指针问题,在释放内存后将指针置为 nullptr
。例如:
#include
int main() {
int* ptr = new int(10);
delete ptr;
ptr = nullptr; // 将指针置为 nullptr
return 0;
}
收起
cpp
#include
class MyClass {
public:
int* data;
MyClass(int value) {
data = new int(value);
}
// 浅拷贝构造函数
MyClass(const MyClass& other) {
data = other.data;
}
~MyClass() {
delete data;
}
};
int main() {
MyClass obj1(10);
MyClass obj2(obj1); // 浅拷贝
// 这里会出现问题,因为 obj1 和 obj2 共享同一块内存
return 0;
}
收起
cpp
#include
class MyClass {
public:
int* data;
MyClass(int value) {
data = new int(value);
}
// 深拷贝构造函数
MyClass(const MyClass& other) {
data = new int(*other.data);
}
~MyClass() {
delete data;
}
};
int main() {
MyClass obj1(10);
MyClass obj2(obj1); // 深拷贝
return 0;
}
智能指针是 C++ 标准库提供的模板类,用于自动管理动态分配的内存,避免手动管理内存带来的问题。常见的智能指针有:
std::unique_ptr
:独占所有权的智能指针,同一时间只能有一个 std::unique_ptr
指向某个对象。例如:收起
cpp
#include
#include
int main() {
std::unique_ptr ptr = std::make_unique(10);
// std::unique_ptr ptr2 = ptr; // 错误,不能复制
std::unique_ptr ptr2 = std::move(ptr); // 可以转移所有权
return 0;
}
std::shared_ptr
:共享所有权的智能指针,多个 std::shared_ptr
可以指向同一个对象,使用引用计数来管理对象的生命周期,当引用计数为 0 时,对象会被自动释放。例如:收起
cpp
#include
#include
int main() {
std::shared_ptr ptr1 = std::make_shared(10);
std::shared_ptr ptr2 = ptr1; // 可以复制
return 0;
}
std::weak_ptr
:弱引用的智能指针,它不拥有对象的所有权,主要用于解决 std::shared_ptr
的循环引用问题。例如:#include
#include
class B;
class A {
public:
std::shared_ptr bPtr;
~A() { std::cout << "A destructor" << std::endl; }
};
class B {
public:
std::weak_ptr aPtr; // 使用 std::weak_ptr 避免循环引用
~B() { std::cout << "B destructor" << std::endl; }
};
int main() {
std::shared_ptr a = std::make_shared();
std::shared_ptr b = std::make_shared();
a->bPtr = b;
b->aPtr = a;
return 0;
}