📍 导航:返回目录 | 上一节:Go核心 | 下一节:Python实战
#include <memory>
// 创建 unique_ptr
std::unique_ptr<int> ptr = std::make_unique<int>(42);
// 访问
std::cout << *ptr << std::endl;
// 转移所有权
std::unique_ptr<int> ptr2 = std::move(ptr);
// 此时 ptr 为 nullptr
// 自定义删除器
auto deleter = [](FILE* fp) { fclose(fp); };
std::unique_ptr<FILE, decltype(deleter)> file(fopen("file.txt", "r"), deleter);特点:
- 不可拷贝,只能移动
- 零开销抽象
- 适用于独占资源管理
// 创建 shared_ptr
std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
// 拷贝(引用计数+1)
std::shared_ptr<int> ptr2 = ptr1;
// 查看引用计数
std::cout << ptr1.use_count() << std::endl; // 输出 2
// 自定义删除器
std::shared_ptr<FILE> file(fopen("file.txt", "r"), [](FILE* fp) { fclose(fp); });原理:引用计数,最后一个引用销毁时释放资源
// 解决循环引用问题
struct Node {
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // 使用 weak_ptr 打破循环
};
// 使用
std::shared_ptr<int> sp = std::make_shared<int>(42);
std::weak_ptr<int> wp = sp;
// 访问(需要先提升为 shared_ptr)
if (auto sp2 = wp.lock()) {
std::cout << *sp2 << std::endl;
} else {
std::cout << "对象已销毁" << std::endl;
}Resource Acquisition Is Initialization:资源获取即初始化
// 文件资源管理
class FileGuard {
public:
FileGuard(const char* filename) {
fp = fopen(filename, "r");
if (!fp) throw std::runtime_error("Failed to open file");
}
~FileGuard() {
if (fp) fclose(fp);
}
// 禁止拷贝
FileGuard(const FileGuard&) = delete;
FileGuard& operator=(const FileGuard&) = delete;
FILE* get() { return fp; }
private:
FILE* fp;
};
// 使用
void readFile() {
FileGuard file("data.txt");
// 使用 file.get()
// 离开作用域自动关闭文件
}RAII 的优势:
- 异常安全
- 自动资源释放
- 避免资源泄漏
// 左值和右值
int a = 10; // a 是左值
int b = a + 5; // a+5 是右值
// 右值引用
int&& rvalue_ref = 20;
// std::move 将左值转为右值
std::string s1 = "hello";
std::string s2 = std::move(s1); // s1 被移动,资源转移到 s2class String {
public:
// 拷贝构造(深拷贝)
String(const String& other) {
size_ = other.size_;
data_ = new char[size_ + 1];
std::strcpy(data_, other.data_);
}
// 移动构造(资源转移)
String(String&& other) noexcept {
data_ = other.data_;
size_ = other.size_;
other.data_ = nullptr; // 防止析构时释放资源
other.size_ = 0;
}
// 移动赋值
String& operator=(String&& other) noexcept {
if (this != &other) {
delete[] data_;
data_ = other.data_;
size_ = other.size_;
other.data_ = nullptr;
other.size_ = 0;
}
return *this;
}
~String() {
delete[] data_;
}
private:
char* data_;
size_t size_;
};性能优势:避免不必要的拷贝,提升性能
#include <thread>
#include <iostream>
void worker(int id) {
std::cout << "Worker " << id << " is running\n";
}
int main() {
std::thread t1(worker, 1);
std::thread t2(worker, 2);
t1.join();
t2.join();
return 0;
}#include <mutex>
std::mutex mtx;
int counter = 0;
void increment() {
std::lock_guard<std::mutex> lock(mtx); // RAII 自动加锁/解锁
++counter;
}
// 或使用 unique_lock(更灵活)
void increment2() {
std::unique_lock<std::mutex> lock(mtx);
++counter;
lock.unlock(); // 可以手动解锁
// 其他操作
}#include <condition_variable>
#include <queue>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;
// 生产者
void producer() {
for (int i = 0; i < 10; ++i) {
{
std::lock_guard<std::mutex> lock(mtx);
data_queue.push(i);
}
cv.notify_one(); // 通知消费者
}
}
// 消费者
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return !data_queue.empty(); }); // 等待数据
int value = data_queue.front();
data_queue.pop();
lock.unlock();
std::cout << "Consumed: " << value << std::endl;
}
}#include <atomic>
std::atomic<int> counter(0);
void increment() {
counter.fetch_add(1, std::memory_order_relaxed);
// 或简写为:counter++;
}
// 原子比较交换(CAS)
int expected = 10;
int desired = 20;
if (counter.compare_exchange_strong(expected, desired)) {
// 成功:counter 从 10 变为 20
} else {
// 失败:expected 被更新为 counter 的当前值
}template<typename T>
class ObjectPool {
public:
ObjectPool(size_t size) {
for (size_t i = 0; i < size; ++i) {
pool_.push_back(std::make_unique<T>());
}
}
T* acquire() {
std::lock_guard<std::mutex> lock(mtx_);
if (pool_.empty()) {
return new T();
}
T* obj = pool_.back().release();
pool_.pop_back();
return obj;
}
void release(T* obj) {
std::lock_guard<std::mutex> lock(mtx_);
pool_.push_back(std::unique_ptr<T>(obj));
}
private:
std::vector<std::unique_ptr<T>> pool_;
std::mutex mtx_;
};// 静态多态,避免虚函数开销
template<typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation() {
std::cout << "Derived implementation\n";
}
};// 编译期计算阶乘
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
// 编译期使用
constexpr int result = factorial(5); // 编译时计算工具检测:
# Valgrind
valgrind --leak-check=full ./program
# AddressSanitizer(推荐)
g++ -fsanitize=address -g program.cpp
./a.out常见原因:
- 忘记 delete
- 异常导致资源未释放
- 循环引用(shared_ptr)
解决方案:使用智能指针和 RAII
检测工具:
# ThreadSanitizer
g++ -fsanitize=thread -g program.cpp
./a.out常见原因:
- 多线程访问共享数据未加锁
- 锁的粒度不当
解决方案:
- 使用 mutex 保护共享数据
- 使用 atomic 原子操作
- 避免共享可变状态
// ❌ 错误示例
int* ptr = new int(42);
delete ptr;
*ptr = 10; // 野指针访问!
// ✅ 正确方式
std::unique_ptr<int> ptr = std::make_unique<int>(42);
// 自动管理生命周期C++ 是系统级编程的首选语言,掌握智能指针、RAII、移动语义对于编写高性能、安全的代码至关重要。
关键要点:
- ✅ 智能指针自动管理内存,避免泄漏
- ✅ RAII 确保资源异常安全
- ✅ 移动语义显著提升性能
- ✅ 使用 Sanitizer 工具检测内存和并发问题
- 《Effective Modern C++》
- 《C++ Concurrency in Action》
- C++ Core Guidelines
💡 思考题:
- unique_ptr 和 shared_ptr 的区别?何时用哪个?
- 什么是移动语义?为什么能提升性能?
- 如何避免 shared_ptr 循环引用?
⏮️ 上一节:Go核心 | ⏭️ 下一节:Python实战