C++ 是一门广泛应用于高性能计算、游戏开发、嵌入式系统和底层系统编程的语言。其核心优势在于对内存的精细控制和接近硬件的操作能力。以下是围绕你提供的“核心学习路径”进行的详细解析与实战示例。


1. 基础语法

变量与数据类型
int a = 10;
double b = 3.14;
char c = 'A';
bool flag = true;
指针与引用
int x = 5;
int* ptr = &x;      // 指针指向x的地址
int& ref = x;       // 引用,ref是x的别名
(*ptr)++;           // x变为6
ref++;              // x变为7
流程控制
if (a > 5) {
    cout << "a is greater than 5\n";
} else {
    cout << "a is not greater than 5\n";
}

for (int i = 0; i < 5; ++i) {
    cout << i << " ";
}
类与对象、继承 / 多态
class Animal {
public:
    virtual void speak() { cout << "Animal speaks\n"; }
};

class Dog : public Animal {
public:
    void speak() override { cout << "Woof!\n"; }  // 多态实现
};

// 使用
Animal* pet = new Dog();
pet->speak();  // 输出: Woof!
delete pet;

2. 核心特性

STL 容器:vector 和 map
#include <vector>
#include <map>
#include <iostream>
using namespace std;

// vector 示例
vector<int> nums = {3, 1, 4, 1, 5};
sort(nums.begin(), nums.end());  // 排序后: 1,1,3,4,5

// map 示例
map<string, int> ages;
ages["Alice"] = 25;
ages["Bob"] = 30;
for (auto& pair : ages) {
    cout << pair.first << ": " << pair.second << endl;
}
内存管理(new/delete)
int* p = new int(42);     // 动态分配一个整数
cout << *p << endl;       // 输出 42
delete p;                 // 释放内存

// 数组版本
int* arr = new int[10];
for (int i = 0; i < 10; ++i) arr[i] = i * i;
delete[] arr;             // 注意使用 delete[]

⚠️ 现代 C++ 推荐使用智能指针(如 unique_ptr, shared_ptr)避免手动管理内存。


3. 实战案例

案例一:数组排序(快速排序)
#include <iostream>
using namespace std;

void quickSort(int arr[], int low, int high) {
    if (low >= high) return;

    int pivot = arr[(low + high) / 2];
    int left = low, right = high;

    while (left <= right) {
        while (arr[left] < pivot) left++;
        while (arr[right] > pivot) right--;
        if (left <= right) {
            swap(arr[left], arr[right]);
            left++;
            right--;
        }
    }

    quickSort(arr, low, right);
    quickSort(arr, left, high);
}

int main() {
    int data[] = {64, 34, 25, 12, 22, 11, 90};
    int n = sizeof(data)/sizeof(data[0]);

    quickSort(data, 0, n - 1);

    for (int i = 0; i < n; ++i)
        cout << data[i] << " ";
    return 0;
}
案例二:猜数字小游戏
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
    srand(time(0));
    int secret = rand() % 100 + 1;
    int guess;

    cout << "Guess the number (1-100): ";
    while (cin >> guess) {
        if (guess == secret) {
            cout << "Congratulations! You guessed it!\n";
            break;
        } else if (guess < secret) {
            cout << "Too low! Try again: ";
        } else {
            cout << "Too high! Try again: ";
        }
    }
    return 0;
}

在现代 C++(尤其是 C++11 及以后标准)中,推荐使用智能指针来自动管理动态内存,避免手动调用 newdelete 导致的内存泄漏、重复释放或异常安全问题。最常用的智能指针是 std::unique_ptrstd::shared_ptr


1. std::unique_ptr:独占所有权

  • 一个对象只能被一个 unique_ptr 拥有。
  • 不可复制,但可移动(move semantics)。
  • unique_ptr 离开作用域时,自动释放其所指向的对象。
示例:
#include <iostream>
#include <memory>  // 必须包含头文件

class MyClass {
public:
    MyClass() { std::cout << "MyClass constructed\n"; }
    ~MyClass() { std::cout << "MyClass destructed\n"; }
    void sayHello() { std::cout << "Hello from MyClass!\n"; }
};

int main() {
    // 创建 unique_ptr
    std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();

    ptr->sayHello();  // 使用 -> 调用成员函数

    // 自动析构:当 main 结束时,ptr 被销毁,对象自动删除
    return 0;
}

✅ 输出:

MyClass constructed
Hello from MyClass!
MyClass destructed
移动语义示例:
auto ptr1 = std::make_unique<MyClass>();
// auto ptr2 = ptr1;        // 错误!不能复制
auto ptr2 = std::move(ptr1); // 正确:转移所有权
// 此时 ptr1 为空,ptr2 拥有对象

2. std::shared_ptr:共享所有权

  • 多个 shared_ptr 可以共享同一个对象。
  • 使用引用计数机制:每当增加一个 shared_ptr,计数 +1;减少则 -1。
  • 当引用计数为 0 时,对象自动销毁。
示例:
#include <iostream>
#include <memory>

int main() {
    // 创建 shared_ptr
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
    {
        std::shared_ptr<MyClass> ptr2 = ptr1;  // 共享所有权
        std::cout << "Reference count: " << ptr1.use_count() << "\n"; // 输出 2
    } // ptr2 离开作用域,计数减为 1

    std::cout << "Reference count: " << ptr1.use_count() << "\n"; // 输出 1
    return 0; // 此时 ptr1 析构,计数变为0,对象被删除
}

✅ 输出:

MyClass constructed
Reference count: 2
Reference count: 1
MyClass destructed

3. 如何创建智能指针?

推荐方式 说明
std::make_unique<T>() C++14 起支持,安全创建 unique_ptr
std::make_shared<T>() 高效创建 shared_ptr,建议优先使用

⚠️ 不要这样写

// ❌ 危险:可能造成内存泄漏(异常中断)
std::function<void()> f(new MyClass(), [](MyClass* p){ delete p; });
// 如果 new MyClass() 成功,但在构造函数后抛出异常,资源将未被管理

✅ 应该使用 make_unique / make_shared 来避免此类问题。


4. 实际应用场景对比

场景 推荐智能指针
工厂模式返回对象 std::unique_ptr<Base>
树节点中的父/子关系(避免循环引用) 子用 std::weak_ptr,父用 std::shared_ptr
多个对象共享同一资源(如缓存) std::shared_ptr
临时动态对象(如局部对象) std::unique_ptr

5. 注意事项

  • 避免 shared_ptr 循环引用(例如 A 指向 B,B 又指向 A),会导致内存无法释放。
  • 使用 std::weak_ptr 解决循环引用问题。
  • 尽量避免从原始指针构造智能指针(容易出错)。
示例:循环引用问题与 weak_ptr 解法
struct Node;
using NodePtr = std::shared_ptr<Node>;
using WeakNode = std::weak_ptr<Node>;

struct Node {
    int id;
    WeakNode parent;  // 使用 weak_ptr 避免循环引用
    Node(int i) : id(i) { std::cout << "Node " << id << " created\n"; }
    ~Node() { std::cout << "Node " << id << " destroyed\n"; }
};

RAII(Resource Acquisition Is Initialization,资源获取即初始化)是 C++ 中一种重要的编程范式,其核心思想是:

将资源的生命周期绑定到对象的生命周期上 —— 资源在对象构造时获取,在对象析构时自动释放。

这里的“资源”不仅指内存,还包括文件句柄、网络连接、互斥锁、数据库连接等任何需要申请和释放的系统资源。


RAII 的基本原理

  1. 构造函数中获取资源(如 new 内存、open 文件)
  2. 析构函数中释放资源(如 delete、close)
  3. 利用 C++ 的确定性析构机制(对象离开作用域时必定调用析构函数),确保资源不会泄漏。
示例:RAII 管理文件
#include <fstream>
#include <iostream>

class FileHandler {
    std::ofstream file;
public:
    FileHandler(const std::string& filename) {
        file.open(filename);
        if (!file.is_open()) {
            throw std::runtime_error("Cannot open file!");
        }
        std::cout << "File opened: " << filename << "\n";
    }

    void write(const std::string& data) {
        file << data << std::endl;
    }

    ~FileHandler() {
        if (file.is_open()) {
            file.close();
            std::cout << "File closed.\n";
        }
    }
};

int main() {
    try {
        FileHandler fh("output.txt");
        fh.write("Hello, RAII!");
        // 离开作用域时自动关闭文件,无需手动调用 close()
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

即使中间发生异常,C++ 的栈展开机制也会调用局部对象的析构函数,从而保证资源被正确释放。


智能指针是 RAII 的典型实现

std::unique_ptrstd::shared_ptr 就是基于 RAII 原则设计的经典工具:

特性 如何体现 RAII
构造时分配内存 make_uniquenew 时获取堆内存
析构时释放内存 离开作用域时自动调用 deletedelete[]
异常安全 即使抛出异常,栈上智能指针仍会析构,防止内存泄漏
示例对比:原始指针 vs RAII(智能指针)

❌ 手动管理容易出错:

void bad_example() {
    MyClass* ptr = new MyClass();
    do_something(); // 如果这里抛出异常
    delete ptr;     // 这行不会执行 → 内存泄漏!
}

✅ 使用 RAII 自动管理:

void good_example() {
    auto ptr = std::make_unique<MyClass>();
    do_something(); // 即使抛出异常,ptr 析构时自动释放内存
} // 自动 delete

RAII 的优势

  • 异常安全:无论是否发生异常,资源都能被释放。
  • 代码简洁:无需在多处写 deleteclose()
  • 避免资源泄漏:只要对象是局部变量或成员变量,就能保证析构。
  • 通用性强:可用于内存、锁、socket、GUI 句柄等所有资源。

其他 RAII 应用示例

1. 锁管理(std::lock_guard
std::mutex mtx;

void thread_safe_func() {
    std::lock_guard<std::mutex> lock(mtx); // 构造时加锁
    // 操作共享数据
    // 析构时自动解锁,即使发生异常也安全
}
2. 自定义资源管理类

比如数据库连接、图形上下文等都可以封装成 RAII 类型。


在这里插入图片描述

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐