TodoList –第一次前端和前后端分离尝试
记录第一次尝试前端与前后端分离项目的过程,以 TodoList 为例串起 Vue、FastAPI 和接口联调。
简要整理 C++ 中 shared_ptr 和 weak_ptr 的关系、使用场景和循环引用问题,是智能指针学习笔记。
整理说明:这篇是早期实践笔记,本次主要修正分类、标签和摘要;正文保留当时的操作记录。若要按现在环境复现,建议结合当前版本文档再核对一遍。
C++智能指针
C++11 引入了 3 个智能指针类型用于解决指针管理问题,防止内存泄露:
智能指针是现代C++中管理动态分配内存的重要工具,它们通过自动管理资源的生命周期,帮助开发者避免常见的内存管理错误,如内存泄漏、野指针等。
unique_ptr 是一种独占所有权的智能指针。当我们独占资源的所有权时,可以使用 std::unique_ptr 对资源进行管理。当 unique_ptr 对象离开其作用域时,它会自动释放所管理的资源。这是基于RAII(资源获取即初始化)思想的典型应用。
例如:
#include
#include
int main() {
std::unique_ptr ptr(new int(42));
std::cout << *ptr << std::endl; // 输出42
return 0; // unique_ptr离开作用域,自动释放资源
}
unique_ptr 不能被复制,但可以被移动。这意味着它非常适合用于那些需要独占资源所有权的场景。
shared_ptr 允许多个智能指针共享同一块内存资源。它使用引用计数来跟踪有多少个智能指针指向相同的资源。只有当最后一个 shared_ptr 被销毁时,资源才会被释放。
例如:
#include
#include
int main() {
std::shared_ptr ptr1 = std::make_shared(42);
std::shared_ptr ptr2 = ptr1; // 共享所有权
std::cout << ptr2.use_count() << std::endl; // 输出2
std::cout << ptr1.use_count() << std::endl; // 输出2
return 0;
}
在这个例子中,ptr1 和 ptr2 都指向同一块内存资源。use_count() 方法返回当前指向该资源的 shared_ptr 的数量。当引用计数为 0 时,资源会被自动释放。
weak_ptr 通常与 shared_ptr 一起使用,用于解决循环引用的问题。weak_ptr 不增加引用计数,只是观察 shared_ptr 的生命周期,不会阻止资源的释放。
例如:
#include
#include
int main() {
std::shared_ptr ptr = std::make_shared(42);
std::weak_ptr weakPtr = ptr;
if (auto sharedPtr = weakPtr.lock()) {
std::cout << *sharedPtr << std::endl; // 输出42
}
return 0; // 在这里ptr被销毁
}
在这个例子中,weakPtr 是一个 weak_ptr,它指向由 ptr 管理的资源。weakPtr.lock() 方法尝试获取一个指向资源的 shared_ptr。如果资源仍然存在,它会返回一个有效的 shared_ptr;否则,它会返回一个空的 shared_ptr。
循环引用是 shared_ptr 使用中常见的问题。例如,两个对象相互引用对方的 shared_ptr,会导致引用计数永不为零,从而导致内存泄漏。
例如:
#include
#include
class B; // forward declaration
class A {
public:
std::shared_ptr bPtr; // shared_ptr to B
~A() {
std::cout << "A destructor called" << std::endl;
}
};
class B {
public:
std::shared_ptr aPtr; // shared_ptr to A
~B() {
std::cout << "B destructor called" << std::endl;
}
};
int main() {
std::shared_ptr aPtr = std::make_shared(); // create a shared_ptr to A
std::shared_ptr bPtr = std::make_shared(); // create a shared_ptr to B
aPtr->bPtr = bPtr; // assign bPtr to bPtr member of A
bPtr->aPtr = aPtr; // assign aPtr to aPtr member of B
return 0; // 由于循环引用,析构函数不会被调用,导致内存泄漏
}
在这个例子中,A 和 B 相互引用对方的 shared_ptr,导致引用计数永不为零,从而导致内存泄漏。
使用 weak_ptr 可以解决这个问题:
#include #include class B; // forward declaration class A { public: std::shared_ptr **bPtr; // shared_ptr to B ~A() { std::cout << "A destructor called" << std::endl; } }; class B { public: std::weak_ptr** **aWeakPtr; // weak_ptr to A ~B() { std::cout << "B destructor called" << std::endl; } }; int main() { std::shared_ptr aPtr = std::make_shared(); // create a shared_ptr to A std::shared_ptr **bPtr = std::make_shared**(); // create a shared_ptr to B aPtr->bPtr = bPtr; // assign bPtr to bPtr member of A bPtr->aWeakPtr = aPtr; // assign aPtr to aWeakPtr member of B return 0; // 现在A和B的析构函数都会被正确调用 }******
在这个修改后的例子中,B 使用 weak_ptr 来引用 A,从而避免了循环引用问题。当 aPtr 和 bPtr 离开作用域时,它们的析构函数都会被正确调用,资源也会被正确释放。
C++11 引入的智能指针是现代C++中管理动态内存的重要工具。unique_ptr 适用于独占资源所有权的场景,shared_ptr 适用于多个指针共享资源的场景,而 weak_ptr 则用于解决循环引用问题。通过合理使用这些智能指针,可以有效避免内存泄漏和其他资源管理问题,使代码更加安全和易于维护。