深入学习C++智能指针之shared_ptr与右值引用的方法

深入学习C++智能指针之shared_ptr与右值引用的方法

本文将介绍C++中的智能指针shared_ptr和右值引用的概念及其用法,其中注意点将在示例中一并说明。

shared_ptr

shared_ptr是C++11中的智能指针,用于管理动态分配内存的生命周期。shared_ptr采用引用计数的机制,每个shared_ptr都能访问同一块内存,当最后一个指向该内存的shared_ptr被销毁时,内存就会被释放。使用shared_ptr能够有效地避免内存泄漏。

shared_ptr的创建

shared_ptr的创建可以通过直接赋值或者make_shared函数来实现。

直接赋值方式

//示例1:
//普通指针的创建
int *p = new int(10);
//shared_ptr的创建
shared_ptr<int> sp(p);

shared_ptr<int>用于指定shared_ptr的类型,sp是shared_ptr的对象名,p是普通指针的名称。当sp析构时,它会自动释放p所指向的内存。

make_shared函数

make_shared函数能够更加方便地创建shared_ptr。

//示例2:
auto sp1 = make_shared<int>(10); //等同于shared_ptr<int> sp(new int(10))
auto sp2 = make_shared<string>("hello"); //等同于shared_ptr<string> sp(new string("hello"))

make_shared函数可以更加简明地创建shared_ptr,类型名和内存分配都通过参数确定。

shared_ptr的使用

shared_ptr的使用方法和常规指针类似,可以通过解引用符号*和箭头符号->来访问存储在shared_ptr中的对象。

//示例3:
auto sp1 = make_shared<int>(10);
auto sp2 = sp1;
cout << *sp1 << " " << *sp2 << endl; //输出:10 10
*sp1 = 20;
cout << *sp1 << " " << *sp2 << endl; //输出:20 20

示例中,sp2也指向了sp1所指向的内存,所以*sp1*sp2的值相同,当对*sp1赋值后,两个指针所指向的值均发生了变化。

shared_ptr的注意点

在使用shared_ptr的过程中,需要注意以下几点。

避免循环引用

循环引用是指两个或者多个对象之间相互引用,这种情况常常会导致内存泄漏。使用shared_ptr的时候,尤其要注意避免循环引用造成的问题。

//示例4:
struct B;
struct A
{
  shared_ptr<B> m_Bptr;
  ~A() {cout << "A deleted" << endl;}
};

struct B
{
  shared_ptr<A> m_Aptr;
  ~B() {cout << "B deleted" << endl;}
};

void Test()
{
  shared_ptr<A> a(new A);
  shared_ptr<B> b(new B);
  a->m_Bptr = b; //A实例持有B实例的shared_ptr 
  b->m_Aptr = a; //B实例持有A实例的shared_ptr
}

在示例4中,A类和B类相互持有对方的shared_ptr,在函数结束时,由于相互持有,导致shared_ptr引用计数不为0,出现内存泄漏的问题。这种情况可以通过使用weak_ptr等方式来避免。

非空判断

在使用shared_ptr的时候,需要对其进行非空判断,以避免使用空指针造成程序崩溃的问题。

//示例5:
void Test(shared_ptr<int> sp)
{
  if(sp) //对shared_ptr进行非空判断
  {
    cout << *sp << endl;
  }
}

int main()
{
  shared_ptr<int> sp;
  Test(sp);
  return 0;
}

在示例5中,如果sp为null,则直接忽略某些逻辑,以避免空指针的使用。

右值引用

右值引用是与左值引用对应的概念,右值指的是表达式传递给函数的临时变量或者和常量,通过右值引用,可以将右值直接绑定到函数中,从而避免复制和引用操作。

右值引用的创建

右值引用使用语法为:类型名&& 变量名

//示例6:
void Func(int&& value)
{
  cout << value << endl;
}

int main()
{
  int a = 10;
  Func(a + 3); //将表达式a+3作为右值直接传递给函数Func
  return 0;
}

在示例6中,a + 3是一个临时变量,通过右值引用,可以将其直接传递给函数Func,以避免复制。在函数中,需要使用std::move来转移右值引用,避免出现悬垂指针的问题。

右值引用的注意点

在使用右值引用时,需要注意以下几点。

不能返回局部变量的引用

右值引用不能返回指向局部变量的指针或者引用,因为局部变量的生命周期与函数调用结束时一致。

//示例7:
int&& Func()
{
  int value = 10;
  return std::move(value); //error: 对 'value' 做右值引用不能将 'value' 作为 'int&&' 的初始值
}

int main()
{
  int&& a = Func();
  cout << a << endl;
  return 0;
}

在示例7中,Func函数返回一个指向局部变量value的右值引用,在返回时value已被销毁,导致悬垂指针的问题。

左值和右值的区别

在使用右值引用时,需要正确地区分左值和右值,以免出现不必要的问题。

//示例8:
void Func(int& value) //对左值参考
{
  cout << "左值" << endl;
}

void Func(int&& value) //对右值引用
{
  cout << "右值" << endl;
}

int main()
{
  int a = 10;
  Func(a); //输出“左值”
  Func(10); //输出“右值”
  return 0;
}

在示例8中,对左值的引用和对右值的引用都是合法的,需要根据实际情况选择正确的引用方式。

总结

本文介绍了C++11中的智能指针shared_ptr和右值引用,包括它们的创建和使用方法,以及需要注意的细节。通过学习本文,可以更加清晰地理解这些概念,并能够灵活应用到实际编程中。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入学习C++智能指针之shared_ptr与右值引用的方法 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • mysqlin排序

    以下是“MySQL中排序”的完整攻略: MySQL中排序 在MySQL中,您可以使用ORDER BY子句对查询结果进行排序。本攻略将介绍如何使用ORDER BY子句对查询结果进行排序。 步骤1:使用ORDER BY子句 ORDER BY子句用于对结果进行排序。以下是ORDER BY子句的语法: SELECT column1, column2, … FRO…

    other 2023年5月7日
    00
  • Python利用FlashText算法实现替换字符串

    当然!下面是关于\”Python利用FlashText算法实现替换字符串\”的完整攻略: Python利用FlashText算法实现替换字符串 FlashText是一种高效的字符串匹配和替换算法,可以在大规模文本中快速查找和替换关键词。以下是使用FlashText算法实现替换字符串的示例: 示例1:替换关键词 from flashtext import Ke…

    other 2023年8月19日
    00
  • UEFI开发实战用户交互界面使用说明VFR文件

    这里我给出关于UEFI开发实战用户交互界面使用说明VFR文件的完整攻略。 什么是VFR文件? VFR是Visual Forms Representation的缩写,是一种为UEFI界面开发的预处理器源文件格式。通过VFR文件,UEFI开发人员可以定义界面元素和语言本地化字符串。 如何创建VFR文件? 一般情况下,我们使用文本编辑器(如Notepad++)创建…

    other 2023年6月27日
    00
  • Android仿外卖购物车功能

    Android仿外卖购物车功能攻略 1. 界面设计 首先,我们需要设计一个用户界面,用于展示购物车中的商品列表和相关操作。可以使用RecyclerView来展示商品列表,每个列表项包含商品名称、价格和数量。还可以添加增加数量和减少数量的按钮,以及删除商品的按钮。 示例代码: <androidx.recyclerview.widget.RecyclerV…

    other 2023年8月26日
    00
  • 平均精度(averageprecision)计算

    以下是关于“平均精度(average precision)计算”的完整攻略,包含两个示例。 平均精度(average precision)计算 平均精度(average precision)是一种用于评估信息检索系统的指标。它是通过计算每个查询的精度和召回率曲线下面积来计算的。平均精度是信息检索系统性能的重要指标之一,通常用于比较不同系统的性能。 1. 计算…

    other 2023年5月9日
    00
  • springboot 配置文件里部分配置未生效的解决

    问题描述: 在使用SpringBoot开发项目时,我们通常会将项目的配置信息保存在application.properties或application.yml配置文件中,在某些情况下,发现部分配置未能按预期生效。 问题解决: 检查配置文件名称和位置是否正确确保配置文件名称拼写正确,位置和文件路径与默认设置一致。应在src/main/resources下创建一…

    other 2023年6月25日
    00
  • 简单创建json格式文件

    简单创建 JSON 格式文件 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它广泛应用于移动端和 Web 应用程序中。本篇文章将介绍如何简单创建 JSON 格式文件。 什么是 JSON 文件 JSON 文件是一种轻量级的数据格式,它由键值对(key-value pairs)构成,且支持嵌套。通常,JSON 文件的…

    其他 2023年3月28日
    00
  • tomcat双击startup.bat闪退的原因及解决方式

    问题描述 当我们想要启动Tomcat时,双击startup.bat后,发现窗口一闪即退,无法启动Tomcat。这个问题在开发Web应用程序时经常会遇到。 原因分析 引起这个问题的原因可能有很多,比如Java环境配置不正确、Tomcat版本不兼容、系统缺失必要的动态链接库等等。但最常见的原因是Java环境配置不正确。 解决方案 环境变量配置 确保系统中已正确配…

    其他 2023年4月16日
    00
合作推广
合作推广
分享本页
返回顶部