• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 关于c++ 智能指针及 循环引用的问题

关于c++ 智能指针及 循环引用的问题

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c++智能指针,c++中指针的用法,c++ void指针,c++文件指针,c++指针等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

c++智能指针介绍

由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete,比如流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见,并造成内存泄露。如此c++引入 智能指针 ,智能指针即是C++ RAII的一种应用,可用于动态资源管理,资源即对象的管理策略。 智能指针在 <memory>标头文件的 std 命名空间中定义。 它们对 RAII 或 获取资源即初始化 编程惯用法至关重要。 RAII 的主要原则是为所有堆分配资源提供所有权,例如动态分配内存或系统对象句柄、析构函数包含要删除或释放资源的代码的堆栈分配对象,以及任何相关清理代码。

c++智能指针类别

c++ 智能指针主要包括:unique_ptr,shared_ptr, weak_ptr, 这三种,其中auto_ptr 已被遗弃。

unique_ptr

只允许基础指针的一个所有者。 可以移到新所有者(具有移动语义),但不会复制或共享(即我们无法得到指向同一个对象的两个unique_ptr)。 替换已弃用的 auto_ptr。 相较于 boost::scoped_ptr。 unique_ptr 小巧高效;大小等同于一个指针,支持 rvalue 引用,从而可实现快速插入和对 STL 集合的检索。 头文件:<memory>。

使用unique_ptr,可以实现以下功能:

1、为动态申请的内存提供异常安全。
2、将动态申请内存的所有权传递给某个函数。
3、从某个函数返回动态申请内存的所有权。
4、在容器中保存指针。
5、所有auto_ptr应该具有的(但无法在C++ 03中实现的)功能。

如下代码所示:

class A;
// 如果程序执行过程中抛出了异常,unique_ptr就会释放它所指向的对象
// 传统的new 则不行
unique_ptr<A> fun1()
{
 unique_ptr p(new A);
 //do something
 return p;
}

void fun2()
{  // unique_ptr具有移动语义
 unique_ptr<A> p = f();// 使用移动构造函数
 // do something
}// 在函数退出的时候,p以及它所指向的对象都被删除释放 shared_ptr 

</div>


采用引用计数的智能指针。 shared_ptr基于“引用计数”模型实现,多个shared_ptr可指向同一个动态对象,并维护了一个共享的引用计数器,记录了引用同一对象的shared_ptr实例的数量。当最后一个指向动态对象的shared_ptr销毁时,会自动销毁其所指对象(通过delete操作符)。shared_ptr的默认能力是管理动态内存,但支持自定义的Deleter以实现个性化的资源释放动作。头文件:<memory>。

基本操作:shared_ptr的创建、拷贝、绑定对象的变更(reset)、shared_ptr的销毁(手动赋值为nullptr或离开作用域)、指定deleter等操作。

shared_ptr的创建,有两种方式,

一,使用函数make_shared(会根据传递的参数调用动态对象的构造函数);

二,使用构造函数(可从原生指针、unique_ptr、另一个shared_ptr创建)

shared_ptr<int> p1 = make_shared<int>(1);// 通过make_shared函数

shared_ptr<int> p2(new int(2));// 通过原生指针构造此外智能指针若为“空“,即不指向任何对象,则为false,否则为true,可作为条件判断。可以通过两种方式指定deleter,一是构造shared_ptr时,二是使用reset方法时。可以重载的operator->, operator *,以及其他辅助操作如unique()、use_count(), get()等成员方法。

weak_ptr

结合 shared_ptr 使用的特例智能指针。 weak_ptr 提供对一个或多个 shared_ptr 实例所属对象的访问,但是,不参与引用计数。 如果您想要观察对象但不需要其保持活动状态,请使用该实例。 在某些情况下需要断开 shared_ptr 实例间的循环引用。 头文件:<memory>。

weak_ptr的用法如下:

weak_ptr用于配合shared_ptr使用,并不影响动态对象的生命周期,即其存在与否并不影响对象的引用计数器。weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象。提供了expired()与lock()成员函数,前者用于判断weak_ptr指向的对象是否已被销毁,后者返回其所指对象的shared_ptr智能指针(对象销毁时返回”空“shared_ptr)。循环引用的场景:如二叉树中父节点与子节点的循环引用,容器与元素之间的循环引用等。

智能指针的循环引用

循环引用问题可以参考 这个链接 上的问题理解,“循环引用”简单来说就是:两个对象互相使用一个shared_ptr成员变量指向对方的会造成循环引用。导致引用计数失效。下面给段代码来说明循环引用:

#include <iostream>
#include <memory>
using namespace std;

class B;
class A
{
public:// 为了省去一些步骤这里 数据成员也声明为public
 //weak_ptr<B> pb;
 shared_ptr<B> pb;
 void doSomthing()
 {
// if(pb.lock())
// {
//
// }
 }

 ~A()
 {
 cout << "kill A\n";
 }
};

class B
{
public:
 //weak_ptr<A> pa;
 shared_ptr<A> pa;
 ~B()
 {
 cout <<"kill B\n";
 }
};

int main(int argc, char** argv)
{
 shared_ptr<A> sa(new A());
 shared_ptr<B> sb(new B());
 if(sa && sb)
 {
 sa->pb=sb;
 sb->pa=sa;
 }
 cout<<"sa use count:"<<sa.use_count()<<endl;
 return 0;
}

</div>

上面的代码运行结果为:sa use count:2, 注意此时sa,sb都没有释放,产生了内存泄露问题!!!

即A内部有指向B,B内部有指向A,这样对于A,B必定是在A析构后B才析构,对于B,A必定是在B析构后才析构A,这就是循环引用问题,违反常规,导致内存泄露。

一般来讲,解除这种循环引用有下面有三种可行的方法( 参考 ):

1 . 当只剩下最后一个引用的时候需要手动打破循环引用释放对象。

2 . 当A的生存期超过B的生存期的时候,B改为使用一个普通指针指向A。

3 . 使用弱引用的智能指针打破这种循环引用。

虽然这三种方法都可行,但方法1和方法2都需要程序员手动控制,麻烦且容易出错。我们一般使用第三种方法:弱引用的智能指针weak_ptr。

强引用和弱引用

一个强引用当被引用的对象活着的话,这个引用也存在(就是说,当至少有一个强引用,那么这个对象就不能被释放)。share_ptr就是强引用。相对而言,弱引用当引用的对象活着的时候不一定存在。仅仅是当它存在的时候的一个引用。弱引用并不修改该对象的引用计数,这意味这弱引用它并不对对象的内存进行管理,在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存。

使用weak_ptr来打破循环引用

代码如下:

#include <iostream>
#include <memory>
using namespace std;

class B;
class A
{
public:// 为了省去一些步骤这里 数据成员也声明为public
 weak_ptr<B> pb;
 //shared_ptr<B> pb;
 void doSomthing()
 {
 if(pb.lock())
 {

 }
 }

 ~A()
 {
 cout << "kill A\n";
 }
};

class B
{
public:
 //weak_ptr<A> pa;
 shared_ptr<A> pa;
 ~B()
 {
 cout <<"kill B\n";
 }
};

int main(int argc, char** argv)
{
 shared_ptr<A> sa(new A());
 shared_ptr<B> sb(new B());
 if(sa && sb)
 {
 sa->pb=sb;
 sb->pa=sa;
 }
 cout<<"sb use count:"<<sb.use_count()<<endl;
 return 0;
}

</div>

以上就是小编为大家带来的关于c++ 智能指针及 循环引用的问题全部内容了,希望大家多多支持~

</div>
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C++中this指针用法详解及实例
  • 关于c++ 智能指针及 循环引用的问题
  • C++智能指针读书笔记
  • 剖析C++编程当中指针作为函数参数的用法
  • 深入解读C++中的指针变量
  • C++基础入门教程(九):函数指针之回调
  • C++基础入门教程(八):函数指针
  • C++普通函数指针与成员函数指针实例解析
  • c++回调之利用函数指针示例
  • C++中的对象指针总结

相关文章

  • 2017-05-28C语言实现的排列组合问题的通用算法、解决方法
  • 2017-05-28C++使struct对象拥有可变大小的数组(详解)
  • 2017-05-28VC++中HTControl控制类使用之CHTDlgBase对话框基类实例
  • 2017-05-28C++文件依存关系介绍
  • 2017-05-28浅析C和C++函数的相互引用
  • 2017-05-28C语言创建和操作单链表数据结构的实例教程
  • 2017-05-28C++构造函数深度学习
  • 2017-05-28C++抽奖程序实现方法
  • 2017-12-31数据结构 最小生成树
  • 2017-05-28C++实现动态分配const对象实例

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C语言double和float 实例分析
    • C语言中的BYTE和char深入解析
    • 解析C++浮点数无效值的定义与无效值判定的小结
    • C语言实现电子邮件地址验证程序
    • C++取得当前时间的方法
    • 利用简洁的C语言代码解决跳台阶问题与约瑟夫环问题
    • C++中I/O模型之select模型实例
    • 可读可执行的C语言简历源文件
    • C语言数据类型转换实例代码
    • C++遍历文件夹获取文件列表

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有