专业网站制作软件,广东省网站集约化建设方案,wordpress xmlrpc 漏洞,学校微网站模板下载地址系列文章目录
【C11】智能指针与动态内存 文章目录 系列文章目录简介一、头文件二、初始化及使用1. 使用一个shared_ptr来初始化 三、循环引用3.1 循环引用3.2 循环引用 解决方法 简介
在C编程中#xff0c;处理循环引用是一个常见的问题。循环引用可能导致内存泄漏和资源管…系列文章目录
【C11】智能指针与动态内存 文章目录 系列文章目录简介一、头文件二、初始化及使用1. 使用一个shared_ptr来初始化 三、循环引用3.1 循环引用3.2 循环引用 解决方法 简介
在C编程中处理循环引用是一个常见的问题。循环引用可能导致内存泄漏和资源管理问题。为了解决这个问题C11引入了weak_ptr智能指针。
弱指针weak_ptr是一种不受控制所指向对象生存期的智能指针它指向由一个shared_ptr管理的对象。允许你共享对象的所有权但不会增加对象的引用计数。它是一种弱引用不会阻止对象的销毁。一旦一个指向对象的shared_ptr被销毁对象就会被释放。即使有weak_ptr指向对象对象也会被释放。 一、头文件
本文出现的关于unique_ptr的方法都包含在此头文件中
#include memory二、初始化及使用
1. 使用一个shared_ptr来初始化
用一个shared_ptr来初始化不会改变shared_ptr的引用计数
auto p std::make_sharedint(4);
std::weak_ptrint wp(p); 由于wp指向的对象可能不存在我们不能使用weak_ptr直接访问对象而必须调用lock。 此函数检查weak_ptr指向的对象是否存在。如果存在lock返回一个指针指向共享对象的shared_ptr否则返回一个空的shared_ptr。 if (std::shared_ptrint np wp.lock()) // 如果np不为空则条件成立
{// np与p共享对象
}三、循环引用
3.1 循环引用
环引用是指两个或多个智能指针相互引用形成一个闭环导致它们都无法被释放从而造成内存泄漏。循环引用通常发生在两个或多个对象之间存在相互依赖关系时它们需要同时被释放。
下述代码就是循环引用的典型例子a和b所指向的对象的引用计数永远不会为0也就不会释放对象。
class B;
class A
{
public:std::shared_ptrB b_ptr;A() {std::cout A Constructor Called std::endl;};~A() {std::cout A Desstructor Called std::endl;};
};class B
{
public:std::shared_ptrA a_ptr; //这里改成weak_ptr即可解决循环引用B() {std::cout B Constructor Called std::endl;};~B() {std::cout B Desstructor Called std::endl;};
};int main()
{ std::shared_ptrA a std::make_sharedA();std::shared_ptrB b std::make_sharedB();std::cout a uses a.use_count() std::endl; // 引用计数输出1std::cout b uses b.use_count() std::endl; // 引用计数输出1a-b_ptr b;b-a_ptr a;std::cout a uses a.use_count() std::endl; // 引用计数输出2std::cout b uses b.use_count() std::endl; // 引用计数输出2std::cout Hello World!\n;
}析构规定 在C中局部变量的析构顺序与它们的构造顺序相反。也就是说最后构造的对象会首先被析构。这被称为栈解旋stack unwinding。 在C中当一个对象被销毁其成员变量的析构函数会在该对象的析构函数之后被调用。也就是说首先调用对象的析构函数然后调用其成员变量的析构函数。确保了在对象的析构函数中你仍然可以访问和操作其成员变量因为它们此时还没有被销毁。 shared_ptr的析构函数会递减它所指向的对象的引用计数。如果引用计数变为0shared_ptr的析构函数就会销毁对象并释放它所占用的内存。 上述代码执行完毕析构函数的调用情况以及引用计数变化情况的说明
①a 和 b 离开作用域之前 a和b-a_ptr指向A的同一个实例对象该对象的引用计数为2 b和a-b_ptr指向B的同一个实例对象该对象的引用计数为2 ②b调用析构函数 a和b离开作用域时b先调用析构函数这会导致b指向对象的引用计数减1但是由于a-b_ptr指向同一个对象所以b指向对象的引用计数仍然为1。 ③b-a_ptr调用析构函数 因为b指向对象的引用计数不为0故其其析构函数没有被执行对象没有被销毁。这导致其成员变量b-a_ptr的析构函数也不会被调用(对象本身没有被销毁的话其成员变量的析构函数不会被调用)a指向对象的引用计数不变仍为2。 ④a调用析构函数 a和b离开作用域时b先调用析构函数然后a调用析构函数这会导致a指向对象的引用计数减1但是由于b-a_ptr也指向同一个对象所以a指向对象的引用计数仍为1。 ⑤a-b_ptr调用析构函数 因为a指向对象的引用计数不为0故其析构函数没有被执行对象没有被销毁。这导致其成员变量a-b_ptr的析构函数也不会被调用b指向对象的引用计数不变仍为1。 最后对象a和b的引用计数都为1不会销毁对象释放内存从而导致内存泄漏。
3.2 循环引用 解决方法
将B类中的shared_ptr改为weak_ptr这样就可以打破循环引用当a和b离开作用域时它们的引用计数会变为0析构函数会被调用内存会被释放。
①a和b离开作用域之前 a指向A的一个实例对象a指向对象的引用计数是1(b-a_ptr弱指针引用计数不会加1) b和a-b_ptr指向B的同一个实例对象b对象b引用计数是2 ②b调用析构函数 a和b离开作用域时b先调用析构函数这会导致b指向对象的引用计数减1但是由于a-b_ptr指向同一个对象所以b指向对象的引用计数仍然为1。 ③b-a_ptr调用析构函数 因为b指向对象的引用计数不为0故其其析构函数没有被执行对象没有被销毁。这导致其成员变量b-a_ptr的析构函数也不会被调用(对象本身没有被销毁的话其成员变量的析构函数不会被调用)a指向对象的引用计数不变仍为1。 ④a调用析构函数 a和b离开作用域时b先调用析构函数然后a调用析构函数这会导致a指向对象的引用计数减1。但因为b-a_ptr是弱指针不会增加引用计数所以a指向对象的引用计数变为0会执行析构函数销毁对象释放内存。 ⑤a-b_ptr调用析构函数 因为a指向对象的引用计数为0故其析构函数被执行对象被销毁。从而其成员变量a-b_ptr的析构函数也会被调用b指向对象的引用计数递减也变为0销毁对象释放内存。 最后对象a和b的引用计数都为0不会导致内存泄漏