Appearance
内存管理
C++提供了手动管理内存的能力,这是C++强大但也容易出错的地方。本章将介绍动态内存分配、智能指针和内存管理最佳实践。
动态内存分配
cpp
#include <iostream>
using namespace std;
int main() {
// ============ new和delete ============
// 动态分配单个对象
int* ptr = new int; // 分配一个int
*ptr = 100;
cout << "*ptr = " << *ptr << endl;
delete ptr; // 释放
ptr = nullptr; // 置空,避免悬空指针
// 初始化
int* ptr2 = new int(42); // 分配并初始化为42
cout << "*ptr2 = " << *ptr2 << endl;
delete ptr2;
// C++11:列表初始化
int* ptr3 = new int{100};
cout << "*ptr3 = " << *ptr3 << endl;
delete ptr3;
// ============ 动态数组 ============
// 分配数组
int* arr = new int[5]; // 分配5个int
// 初始化数组
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
cout << "\n动态数组: ";
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
cout << endl;
delete[] arr; // 释放数组(注意用delete[])
// C++11:初始化列表
int* arr2 = new int[5]{1, 2, 3, 4, 5};
cout << "初始化数组: ";
for (int i = 0; i < 5; i++) {
cout << arr2[i] << " ";
}
cout << endl;
delete[] arr2;
// ============ 二维数组 ============
// 分配二维数组
int rows = 3, cols = 4;
int** matrix = new int*[rows];
for (int i = 0; i < rows; i++) {
matrix[i] = new int[cols];
}
// 使用
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j;
}
}
cout << "\n二维数组:" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << matrix[i][j] << "\t";
}
cout << endl;
}
// 释放二维数组
for (int i = 0; i < rows; i++) {
delete[] matrix[i];
}
delete[] matrix;
// ============ 处理分配失败 ============
try {
// 可能失败的分配
// int* huge = new int[1000000000000];
}
catch (const bad_alloc& e) {
cerr << "内存分配失败: " << e.what() << endl;
}
// nothrow版本(不抛出异常)
int* safe = new(nothrow) int[1000];
if (safe == nullptr) {
cerr << "分配失败" << endl;
} else {
delete[] safe;
}
return 0;
}智能指针详解
cpp
#include <iostream>
#include <memory>
using namespace std;
class Resource {
public:
string name;
Resource(string n) : name(n) {
cout << "创建: " << name << endl;
}
~Resource() {
cout << "销毁: " << name << endl;
}
void use() {
cout << "使用: " << name << endl;
}
};
int main() {
// ============ unique_ptr ============
cout << "===== unique_ptr =====" << endl;
// 创建方式
unique_ptr<Resource> up1(new Resource("资源1"));
auto up2 = make_unique<Resource>("资源2"); // 推荐
up1->use();
up2->use();
// 独占所有权,不能复制
// unique_ptr<Resource> up3 = up1; // 错误
// 可以移动
unique_ptr<Resource> up3 = move(up1);
if (up1 == nullptr) {
cout << "up1已转移" << endl;
}
// 获取原始指针
Resource* raw = up3.get();
raw->use();
// 释放所有权
Resource* released = up3.release();
delete released; // 手动删除
// 重置
up2.reset(); // 释放并置空
up2.reset(new Resource("新资源")); // 释放旧的,指向新的
// ============ shared_ptr ============
cout << "\n===== shared_ptr =====" << endl;
// 创建
shared_ptr<Resource> sp1 = make_shared<Resource>("共享资源");
cout << "引用计数: " << sp1.use_count() << endl; // 1
{
shared_ptr<Resource> sp2 = sp1; // 共享所有权
cout << "引用计数: " << sp1.use_count() << endl; // 2
shared_ptr<Resource> sp3 = sp1;
cout << "引用计数: " << sp1.use_count() << endl; // 3
sp2->use();
}
cout << "引用计数: " << sp1.use_count() << endl; // 1
// 自定义删除器
shared_ptr<FILE> file(
fopen("test.txt", "w"),
[](FILE* f) {
if (f) {
fclose(f);
cout << "文件已关闭" << endl;
}
}
);
// ============ weak_ptr ============
cout << "\n===== weak_ptr =====" << endl;
shared_ptr<Resource> shared = make_shared<Resource>("弱引用资源");
weak_ptr<Resource> weak = shared;
cout << "shared计数: " << shared.use_count() << endl; // 1
cout << "weak计数: " << weak.use_count() << endl; // 1(不影响)
// 使用weak_ptr需要lock
if (auto locked = weak.lock()) {
locked->use();
}
// 检查是否过期
shared.reset();
if (weak.expired()) {
cout << "资源已释放" << endl;
}
// ============ 解决循环引用 ============
cout << "\n===== 循环引用问题 =====" << endl;
class Node {
public:
string name;
shared_ptr<Node> next; // 使用shared_ptr会导致循环引用
weak_ptr<Node> prev; // 使用weak_ptr打破循环
Node(string n) : name(n) {
cout << "创建节点: " << name << endl;
}
~Node() {
cout << "销毁节点: " << name << endl;
}
};
{
auto node1 = make_shared<Node>("节点1");
auto node2 = make_shared<Node>("节点2");
node1->next = node2;
node2->prev = node1; // 使用weak_ptr,不会增加引用计数
cout << "离开作用域" << endl;
}
// 两个节点都会被正确销毁
return 0;
}内存管理最佳实践
cpp
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
// ============ RAII类 ============
class FileHandle {
private:
FILE* file;
public:
FileHandle(const char* filename, const char* mode)
: file(fopen(filename, mode)) {
if (!file) {
throw runtime_error("无法打开文件");
}
}
~FileHandle() {
if (file) {
fclose(file);
}
}
// 禁止拷贝
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
// 允许移动
FileHandle(FileHandle&& other) noexcept : file(other.file) {
other.file = nullptr;
}
FileHandle& operator=(FileHandle&& other) noexcept {
if (this != &other) {
if (file) fclose(file);
file = other.file;
other.file = nullptr;
}
return *this;
}
FILE* get() const { return file; }
};
// ============ 动态数组类 ============
template<typename T>
class DynamicArray {
private:
unique_ptr<T[]> data;
size_t size_;
size_t capacity_;
public:
DynamicArray() : size_(0), capacity_(10) {
data = make_unique<T[]>(capacity_);
}
void push_back(const T& value) {
if (size_ >= capacity_) {
// 扩容
size_t newCapacity = capacity_ * 2;
auto newData = make_unique<T[]>(newCapacity);
for (size_t i = 0; i < size_; i++) {
newData[i] = move(data[i]);
}
data = move(newData);
capacity_ = newCapacity;
}
data[size_++] = value;
}
T& operator[](size_t index) {
return data[index];
}
const T& operator[](size_t index) const {
return data[index];
}
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
T* begin() { return data.get(); }
T* end() { return data.get() + size_; }
};
int main() {
// 使用RAII类
try {
FileHandle fh("test.txt", "w");
fputs("Hello, RAII!", fh.get());
// 自动关闭
}
catch (const exception& e) {
cerr << e.what() << endl;
}
// 使用动态数组类
DynamicArray<int> arr;
for (int i = 0; i < 20; i++) {
arr.push_back(i * 10);
}
cout << "\n动态数组: ";
for (size_t i = 0; i < arr.size(); i++) {
cout << arr[i] << " ";
}
cout << endl;
cout << "大小: " << arr.size() << ", 容量: " << arr.capacity() << endl;
// 使用范围for
cout << "范围for: ";
for (int n : arr) {
cout << n << " ";
}
cout << endl;
return 0;
}本章小结
本章学习了:
- 动态内存分配:new、delete、new[]、delete[]
- 智能指针:unique_ptr、shared_ptr、weak_ptr
- RAII:资源获取即初始化
- 最佳实践:避免内存泄漏、使用智能指针
下一章,我们将学习高级特性,了解C++11/14/17/20的新特性。
